标签:异常 机制 行操作 list 扩容 冲突 code 内存数据 效率
1、默认容量?
HashTable默认容量为11,计算hash的方式为如下:
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
根据证明,对素数或奇数直接取模,分布的会更均匀。
其它Map的默认容量都为16,HashMap计算Hash的方式如下:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
static int indexFor(int h, int length) {
return h & (length-1);
}
concurrentHashMap计算Hash的方式如下:
static final int spread(int h) {
return (h ^ (h >>> 16)) & HASH_BITS;
}
第一步计算hash采用了扰动的算法,防止不同hashCode的高位不同但低位相同导致的hash冲突。
第二步计算index采用了位运算。位运算(&)效率要比代替取模运算(%)高很多,主要原因是位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。
那么,为什么可以使用位运算(&)来实现取模运算(%)呢?这实现的原理如下:
X % 2^n = X & (2^n - 1)
2^n表示2的n次方,也就是说,一个数对2^n取模 == 一个数和(2^n - 1)做按位与运算 。
假设n为3,则2^3 = 8,表示成2进制就是1000。2^3 -1 = 7 ,即0111。
此时X & (2^3 - 1) 就相当于取X的2进制的最后三位数。
从2进制角度来看,X / 8相当于 X >> 3,即把X右移3位,此时得到了X / 8的商,而被移掉的部分(后三位),则是X % 8,也就是余数。
2、扩容机制:默认扩容因子都是0.75,HashTable扩容为2*length+1,其它扩容为2*length。扩容机制、默认容量、hash计算是密切相关的。
3、实现方式:Hashtable 继承了 Dictionary类,而 HashMap 继承的是 AbstractMap 类。
4、迭代器不同:HashMap 中的 Iterator 迭代器是 fail-fast 的,而 Hashtable 的 Enumerator 不是 fail-fast 的。
5、Hashtable 是不允许键或值为 null 的,HashMap 的键值则都可以为 null。
因为Hashtable在我们put 空值的时候会直接抛空指针异常,但是HashMap却做了特殊处理。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Hashtable使用的是安全失败机制(fail-safe),这种机制会使你此次读到的数据不一定是最新的数据。
如果你使用null值,就会使得其无法判断对应的key是不存在还是为空,因为你无法再调用一次contain(key)来对key是否存在进行判断,ConcurrentHashMap同理。
HashMap、HashTable、SycronizedMap、ConcurrentHashMap、ConcurrentSkipListMap简单总结
标签:异常 机制 行操作 list 扩容 冲突 code 内存数据 效率
原文地址:https://www.cnblogs.com/minikobe/p/12095704.html