Hashtable源码分析
轉自https://blog.csdn.net/duoduo18up/article/details/80167074
1.定義
public class Hashtable<K,V> extends Dictionary<K,V>implements Map<K,V>,Cloneable,java.io.Serializable繼承自Dictionary。
- Dictionary是一個抽象父類,功能和Map一樣,但過時了,官方推薦使用Map接口來替代。
實現了Map接口,以及Cloneable,Serializable接口。
2.和HashMap的區別
2.1 null值的問題
Hashtable的鍵(key)和值(value)均不能為null
/** * 將key和value加入到map中,明顯標明, * value不能為null。如果key為null,則會報NullPointerException異常 * */ public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the Hashtable.Entry<?,?> tab[] = table;int hash = key.hashCode();//很直接的利用hashCode去除table.length,然后取長度。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)) {//hash相同且equals,那么就連在后面,是用鏈表的方式。V old = entry.value;entry.value = value;return old;}}//第一個,鏈表后面沒有數據。addEntry(hash, key, value, index);return null; }關于value,明顯有if判斷,不能為null。
如果key為null,則也直接在計算hashCode的時候就會報空指針異常。
2.2 計算table數組索引值的方法
int hash=key.hashCode();//直接用hashcode%n int index=(hash&0x7FFFFFFF)%tab.length而HashMap中:
int index=e.hash%n;hash值的計算方法不同,很直接地利用hashCode去除table.length,然后取余數。
2.3 Hashtable是線程安全的
因為Hashtable中的大多數方法都是加了synchronized關鍵字,所以同一時刻只能有一個線程進入其方法,故是線程安全的。
2.4initialCapacity和loadFactor
HashMap中:initialCapacity=16,loadFactor=0.75;
Hashtable中:initialCapacity=11,loadFactor=0.75;
2.5解決沖突的方式
HashMap:鏈表/紅黑樹
- 沖突數量<8,以鏈表方式解決沖突
- 沖突數量>=8,將沖突的Entry轉換為紅黑樹進行存儲
- 又當沖突數量<6時,有轉換為鏈表進行存儲
Hashtable:只有鏈表
2.6 擴容的額度
HashMap中:一旦擴容,都是擴展到2的倍數。因為這樣有利于計算數組索引值。即,和計算數組索引結合起來
Hashtable中:一次性擴展為oldCapacity*2+1
/*** 一次擴展是,old*2+1 */ @SuppressWarnings("unchecked") protected void rehash() {int oldCapacity = table.length;Entry<?,?>[] oldMap = table;// overflow-conscious codeint newCapacity = (oldCapacity << 1) + 1;if (newCapacity - MAX_ARRAY_SIZE > 0) {if (oldCapacity == MAX_ARRAY_SIZE)// Keep running with MAX_ARRAY_SIZE bucketsreturn;newCapacity = MAX_ARRAY_SIZE;}Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];modCount++;//新的threshold值。取newCapacity*loadFactor的小值。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;}} }先擴展,再把就數組里面的元素一個一個添加到新的里面。
注意:這里取hash而不是e.hash,而仍然是key.hashCode計算保留下來的值。
總結
以上是生活随笔為你收集整理的Hashtable源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java内存模型、volatile、原子
- 下一篇: volatile、synchronize