1.代码版本
HashTable
* @author Arthur van Hoff
* @author Josh Bloch
* @author Neal Gafter
* @see Object#equals(java.lang.Object)
* @see Object#hashCode()
* @see Hashtable#rehash()
* @see Collection
* @see Map
* @see HashMap
* @see TreeMap
* @since JDK1.0
*/
HashMap
* @author Doug Lea 道格.利亚(Effective Java作者)
* @author Josh Bloch
* @author Arthur van Hoff
* @author Neal Gafter
* @see Object#hashCode()
* @see Collection
* @see Map
* @see TreeMap
* @see Hashtable
* @since 1.2
*/
-
HashTable是java从1.1版本就提供的键值映射的数据结构
-
HashTable是线程安全的,效率比较低,慢慢就被hashMap替代了
-
HashMap是1.2版本开始提供的
2. 继承的父类
//HashTable
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
//HashMap
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
- 首先它们两个都实现了Map , 克隆 , 可序列化三个接口
- HashMap 继承父类的是AbstractMap
- HashTable继承的父类是Dictionary
3 . 对Null key 和Null value支持不同
HashTable :
不支持value ==null ,会抛出异常
不支持key == null , 在hash(k)中调用了K.hashCode()方法,相当于调用null的方法,会抛出空指针异常
hashMap:
在处理key == null时,将其hash值设为0 ,将其放在table[0]的桶中,由源码可知,
key ==null
的Entry只能有一个
.
- 每次传入keynull处理时,先在table[0]找keynull用新值替换旧值
- 没有找到,则
addEntry(0, null, value, 0)(将其作为新的Entry添加)
,此时的hash值被设为0
public V put(K key, V value) {
//key为null时,调用putFullNullKey()进行处理
if (key == null)
return putForNullKey(value);
}
private V putForNullKey(V value) {
// key为null时,放到table[0]的桶中
for (Entry<K,V> e = table[0]; e != null; e = e.next) { // 在table[0]的桶中遍历,找到key为null的Entry
if (e.key == null) {
V oldValue = e.value; // 更改key为null的value值
e.value = value;
e.recordAccess(this);
return oldValue;//返回旧值
}
}
modCount++;
addEntry(0, null, value, 0); //没有在桶中找到,直接 添加这个Entry到0号桶中
return null;
}
4. 初始化大小不同
HashTable的初始大小是11
, hashMap 的初始大小为16
5. 扩容大小不相同
//HashTable二倍+1扩容
int newCapacity = (oldCapacity << 1) + 1;//扩容为2倍加1
//hashMap二倍扩容
resize(2 * table.length);
5.加载时机
hashTable 在构造函数时初始化
hashMap 在添加第一个元素时初始化
6. 计算index值时(扰动处理)
- HashMap对任何key都进行了扰动处理
- HashTable对
String类型的key
提供可选的扰动,对于其他类型默认没有扰动- useAltHashing=…计算是否对字符串键的HashMap使用备选哈希函数
//hashMap
进行了扰动处理,降低了碰撞的几率
h ^= k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12); //进行扰动
return h ^ (h >>> 7) ^ (h >>> 4);
}
// HashTable
if (useAltHashing) { //useAltHashing=...计算是否对字符串键的HashMap使用备选哈希函数
if (k.getClass() == String.class) {
return sun.misc.Hashing.stringHash32((String) k);
} else {
int h = hashSeed ^ k.hashCode();
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
} else {
return k.hashCode(); // 返回未扰动处理的hash值
}
// HashTable 如果没有扰动,则hash值可能为负
// 用hash& 0[31个1]( 0x7FFFFFFF)转换为正数
int index = (hash & 0x7FFFFFFF) % tab.length;
7. 线程安全
HashTable的公开的方法都实现了synchronized描述符 ,因而其是线程安全的.
HashMap为线程非安全的