小花: 原来hashMap的containsKey还有这么个陷阱,以后肥婆要小心了。
第四个不同就是它们两个Hash值的获取方式了。
还是通过源代码源代码,Hashtable是直接使用key对象的hash值。
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = key.hashCode();//hashcode
int index = (hash & 0x7FFFFFFF) % tab.length;
//…
}
而HashMap则是利用key对象的hash值重新计算一个新的hash值。
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());//hashcode
int i = indexFor(hash, table.length);
//…
}
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
小花:胖子,都用了hash算法,你给我讲讲Hash算法吧。
小胖:嗯……以后的,今天我比较忙(其实是不会)。
小花:你是不是不会啊?嘿嘿(坏笑)。
小胖:什么不会……谈下一话题……
第五个不同就是Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。
HashMap中内部数组的初始容量是16, 加载因子为0.75,而且数组容量增容后也要是2指数次幂:
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 16;
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
HashTable中的内部数组的初始容量是11,加载因子也是0.75数组的增容方式为(oldCapacity * 2 + 1):
public Hashtable() {
this(11, 0.75f);
}
protected void rehash() {
int oldCapacity = table.length;
Entry[] oldMap = table;
int newCapacity = oldCapacity * 2 + 1;
//…
}
第六个不同我们从它们两个遍历方式的内部实现上来说。
Hashtable HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
小花:Iterator和Enumeration的区别是什么啊?给我讲讲。
小胖:我不是说我没有时间嘛,下回的。
小花:我都记下来,省得你给我混过去。(拿起笔开始记账中)
小胖:……(紧张)
第七个不同时它们的拷贝构造函数的不同。
依然是通过查看源码,可以发现它们两个对于拷贝函数初始容量的不同值。
HashMap的实现是: