首先看两个类
public class HashMap extends AbstractMap implements Map, Cloneable, Serializable
public class Hashtable extends Dictionary implements Map, Cloneable, java.io.Serializable
Dictionary
类是任何可将键映射到相应值的类(如 Hashtable
)的抽象父类。每个键和每个值都是一个对象。在任何一个 Dictionary 对象中,每个键至多与一个值相关联。给定一个 Dictionary 和一个键,就可以查找所关联的元素。任何非 null
对象都可以用作键或值。
通常,应该在此类的实现中使用 equals
方法,以决定两个键是否相同。
1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个区别就像Vector和ArrayList一样。
2.HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。
3.HashTable有一个contains(Object value),功能和containsValue(Object value)功能一样。
4.HashTable使用Enumeration,(继承与Dictionary ,获取到值得枚举)HashMap使用Iterator。
以上只是表面的不同,它们的实现也有很大的不同。
5.HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
6. 哈希值的使用不同,HashTable直接使用对象的hashCode,代码是这样的:
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
而HashMap重新计算hash值,而且用与代替求模:
int hash = hash(k);
int i = indexFor(hash, table.length);
static int hash(Object x) {
int h = x.hashCode();
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
static int indexFor(int h, int length) {
return h & (length-1);
}
7. HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
8.HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
9. 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步(Collections.synchronizedMap)。
HashTable的实现如下
1 public synchronized V put(K key, V value) { //###### 注意这里1 2 // Make sure the value is not null 3 if (value == null) { //###### 注意这里 2 4 throw new NullPointerException(); 5 } 6 // Makes sure the key is not already in the hashtable. 7 Entry tab[] = table; 8 int hash = key.hashCode(); //###### 注意这里 3 9 int index = (hash & 0x7FFFFFFF) % tab.length;//####注意4 10 for (Entry e = tab[index]; e != null; e = e.next) { 11 if ((e.hash == hash) && e.key.equals(key)) { 12 V old = e.value; 13 e.value = value; 14 return old; 15 } 16 } 17 modCount++; 18 if (count >= threshold) { 19 // Rehash the table if the threshold is exceeded 20 rehash(); 21 tab = table; 22 index = (hash & 0x7FFFFFFF) % tab.length; 23 } 24 // Creates the new entry. 25 Entry e = tab[index]; 26 tab[index] = new Entry(hash, key, value, e); 27 count++; 28 return null; 29 }
注意1 方法是同步的,加了synchronized关键字
注意2 方法不允许value==null
注意3 方法调用了key的hashCode方法,如果key==null,会抛出空指针异常 HashMap的put方法如下
注意3 HashTable直接使用对象的hashCode
HashMap的实现如下
1 public V put(K key, V value) { //###### 注意这里 1 2 if (key == null) //###### 注意这里 2 3 return putForNullKey(value); 4 int hash = hash(key.hashCode()); 5 int i = indexFor(hash, table.length); 6 for (Entry e = table[i]; e != null; e = e.next) { 7 Object k; 8 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 9 V oldValue = e.value; 10 e.value = value; 11 e.recordAccess(this); 12 return oldValue; 13 } 14 } 15 modCount++; 16 addEntry(hash, key, value, i); //###### 注意这里 17 return null; 18 }
注意1 方法是非同步的
注意2 方法允许key==null
注意3 方法并没有对value进行任何调用,所以允许为null