阅读博客
java提高篇(二五)—–HashTable
这篇博客由chenssy 发表与2014年4月,基于源码是jdk1.7
==========================
本文针对jdk1.8的HashTable源码补充说明
put方法
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;
// 直接使用key的hashCode作为hash值。 int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for(; entry != null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; }
HashTable的key和value都不能为null
HashTable不会对key的hashCode进行再哈希,直接使用。
在取table的索引时,先取hash的低31位,然后对table的长度取模。这样速度比HashMap要慢。HashMap已经考虑到这个问题,所以HashMap的table长度
是2的n次方,直接按位计算,就能得到索引,而不需要%计算了。
put使用了synchronize修饰,多线程安全。
在每次添加元素时,会判断当前元素数量是否超过了阈值,超过了,就要rehash,进行扩容。
jdk1.8 rehash源码
protected void rehash() { int oldCapacity = table.length; Entry<?,?>[] oldMap = table; // overflow-conscious code int newCapacity = (oldCapacity << 1) + 1; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) // Keep running with MAX_ARRAY_SIZE buckets return; newCapacity = MAX_ARRAY_SIZE; } Entry<?,?>[] newMap = new Entry<?,?>[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); table = newMap; for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = (Entry<K,V>)newMap[index]; newMap[index] = e; } } }
在chenssy的博客中,下面这行有笔误,少了数组的长度。
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
jdk1.8 get方法源码
public synchronized V get(Object key) { Entry tab[] = table; int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return e.value; } } return null; }
看完了Hashtable和HashMap,发现他们的存储结构上区别是在很小,但还是有一些区别,列举如下
1,Hashtable是同步的,用synchronize修饰了get方法和put方法。而HashMap 没有这个修饰,
2,HashTable不允许key和value为null,HashMap允许。
3,HashTable使用的是Enumerator迭代器,不是fail-fast的, HashMap的迭代器更多,而且是fail-fast的。
4,他们的hash函数不同。但这个问题吧,其实就算是HashMap在不同的jdk版本中,hash函数也不同。HashTable不会对key的hashCode进行再哈希。HashMap会对key的hashCode再hash。
5,table的容量不容,HashMap的table容量总是2的n次方,这样方便了计算index值,提高了效率。HashTable的table容量比较随意,默认值是11,所以计算index时要费劲些。
HashMap在性能上要好于HashTable.
6,HashTable继承自Dictionary,实现了Map接口, HashMap继承自AbstractMap,实现了Map接口。
HashTable比较老,jdk1.0就有了
HashMap和 TreeMap jdk1.2才有
ConcurrentHashMap jdk1.5才有。
区别方面参考博客
http://www.importnew.com/7010.html (HashMap和Hashtable的区别)