一 HashMap类和Hashtable类的介绍

1 HashMap类和Hashtable类概述

HashMap和Hashtable都是Map接口的典型实现类,他们之间的关系完全类似于ArrayList和Vector的关系。

2 HashMap类和Hashtable类的区别

  • Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的实现,所以HashMap比Hashtable的性能高一点;但如果有多线程访问同一个Map对象时,使用Hashtable实现类会更好。
  • Hashtable不允许使用null作为key和value,如果试图把null值放进Hashtable中,将会引发NullPointerException异常;但HashMap可以使用null作为key或value。

3 代码示例

import java.util.*;

public class NullInHashMap
{
	public static void main(String[] args)
	{
		HashMap hm = new HashMap();
		// 试图将两个key为null的key-value对放入HashMap中
		hm.put(null , null);
		hm.put(null , null);    // ①
		// 将一个value为null的key-value对放入HashMap中
		hm.put("a" , null);    // ②
		// 输出Map对象
		System.out.println(hm);
	}
}

4 运行结果

{null=null, a=null}

5 结果分析

由于HashMap里的key不能重复,所以HashMap里最多只有一个key-value对的key为null,但可以由无数多个key-value对的value为null,该程序演示了用null值作为HashMap的key和value的情形。 

二 Hashtable类的典型应用

1 代码示例

import java.util.*;


class A
{
	int count;
	public A(int count)
	{
		this.count = count;
	}
	// 根据count的值来判断两个对象是否相等。
	public boolean equals(Object obj)
	{
		if (obj == this)
			return true;
		if (obj != null && obj.getClass() == A.class)
		{
			A a = (A)obj;
			return this.count == a.count;
		}
		return false;
	}
	// 根据count来计算hashCode值。
	public int hashCode()
	{
		return this.count;
	}
}
class B
{
	// 重写equals()方法,B对象与任何对象通过equals()方法比较都返回true
	public boolean equals(Object obj)
	{
		return true;
	}
}
public class HashtableTest
{
	public static void main(String[] args)
	{
		Hashtable ht = new Hashtable();
		ht.put(new A(60000) , "爸爸");
		ht.put(new A(87563) , "妈妈");
		ht.put(new A(1232) , new B());
		System.out.println(ht);
		// 只要两个对象通过equals比较返回true,
		// Hashtable就认为它们是相等的value。
		// 由于Hashtable中有一个B对象,
		// 它与任何对象通过equals比较都相等,所以下面输出true。
		System.out.println(ht.containsValue("测试字符串")); // ① 输出true
		// 只要两个A对象的count相等,它们通过equals比较返回true,且hashCode相等
		// Hashtable即认为它们是相同的key,所以下面输出true。
		System.out.println(ht.containsKey(new A(87563)));   // ② 输出true
		// 下面语句可以删除最后一个key-value对
		ht.remove(new A(1232));    //③
		System.out.println(ht);
	}
}

2 运行结果

{A@ea60=爸爸, A@1560b=妈妈, A@4d0=B@1db9742}
true
true
{A@ea60=爸爸, A@1560b=妈妈}

3 结果分析

当使用自定义类作为Hashtable的key时,如果重写该类的equals和hashCode方法,则应该保证这两个方法的判断标准一致,当两个Key通过equals方法比较返回true时,两个key的hashCode返回值也应该相同。 

三 HashMap类的典型应用

1 代码示例

import java.util.*;

public class HashMapErrorTest
{
	public static void main(String[] args)
	{
		HashMap ht = new HashMap();
		// 此处的A类与前一个程序的A类是同一个类
		ht.put(new A(60000) , "孙悟空");
		ht.put(new A(87563) , "八戒");
		// 获得Hashtable的key Set集合对应的Iterator迭代器
		Iterator it = ht.keySet().iterator();
		// 取出Map中第一个key,并修改它的count值
		A first = (A)it.next();
		first.count = 87563;   // ①
		// 输出{A@1560b=孙悟空, A@1560b=八戒}
		System.out.println(ht);
		// 只能删除没有被修改过的key所对应的key-value对
		ht.remove(new A(87563));
		System.out.println(ht);
		// 无法获取剩下的value,下面两行代码都将输出null。
		System.out.println(ht.get(new A(87563)));   // ② 输出null
		System.out.println(ht.get(new A(60000)));   // ③ 输出null
	}
}

2 运行结果

{A@1560b=孙悟空, A@1560b=八戒}
{A@1560b=孙悟空}
null
null

3 结果分析

与HashSet类似,尽量不要使用可变变量作为HashMap的key。如果确实需要使用可变变量作为HashMap的key,则尽量不要在程序中修改作为key的可变变量。