深入JDK原始碼之Hashtable

2021-07-27 20:32:05 字數 4355 閱讀 7149

/**

* the hash table data.

*/private

transient entry<?,?> table; // hashmap中的table使用預設修飾符,即同一包內可見

/**

* hashtable bucket collision list entry

*/private

static

class entryimplements map.entry

@suppresswarnings("unchecked")

protected object clone()

// map.entry ops

public k getkey()

public v getvalue()

public v setvalue(v value)

public boolean equals(object o)

public

inthashcode()

public string tostring()

}

hashmap中使用了node實現陣列,而在hashtable中使用了entry,並且是私有的。在hashmap中key和value都可以為空,而在hashtable中key和value都不能為空。

/**

* the total number of entries in the hash table.

* 當前表中的entry數量,如果超過了閾值,就會擴容,即呼叫rehash方法

*/private

transient

int count;

/**

* 載入因子,預設為0.75f

*/private

float loadfactor;

/*** 閾值,值為 (int)math.min(initialcapacity * loadfactor, max_array_size + 1)

* initialcapacity可以由使用者指定,如果不指定,那麼預設為11,即hashtable預設閾值為8

* hashtable預設大小是11是因為除(近似)質數求餘的分散效果好

*/private

int threshold;

/*** 用來實現「fail-fast」機制的(也就是快速失敗)。所謂快速失敗就是在併發集合中,其進行

* 迭代操作時,若有其他執行緒對其進行結構性的修改,這時迭代器會立馬感知到,並且立即丟擲

* concurrentmodificationexception異常,而不是等到迭代完成之後才告訴你(你已經出錯了)。

* 參考文章:

*/private

transient

int modcount = 0;

這就是hashtable的主要屬性。

原始碼:

// 使用 synchronized 關鍵字保證執行緒安全

public

synchronized v put(k key, v value)

// makes sure the key is not already in the hashtable.

entry<?,?> tab = table;

/**

* 這就是為什麼key不能為空的原因,key的hashcode是呼叫object的hashcode()方法,

* 是native的方法,如果為null,就會丟擲空指標異常

*/int hash = key.hashcode();

/**

* 因為hash可能為負數,所以就先和0x7fffffff相與

* 在hashmap中,是用 (table.length - 1) & hash 計算要放置的位置

*/int index = (hash & 0x7fffffff) % tab.length;

@suppresswarnings("unchecked")

entryentry = (entry)tab[index];

for(; entry != null ; entry = entry.next)

}// 如果key對應的值不存在,就呼叫addentry方法加入

addentry(hash, key, value, index);

return

null;

}

接下來看addentry(hash, key, value, index)方法。

private

void addentry(int hash, k key, v value, int

index)

// creates the new entry.

@suppresswarnings("unchecked")

entrye = (entry) tab[index];

// 和hashmap不同,hashtable選擇把新插入的元素放到鍊錶最前邊,而且沒有使用紅黑樹

tab[index] = new entry<>(hash, key, value, e);

count++;

}

@suppresswarnings("unchecked")

protected

void

rehash()

entry<?,?> newmap = new entry<?,?>[newcapacity];

modcount++;

threshold = (int)math.min(newcapacity * loadfactor, max_array_size + 1);

table = newmap;

for (int i = oldcapacity ; i-- > 0 ;)

}}

@suppresswarnings("unchecked")

public

synchronized v get(object key)

}return

null;

}

get方法沒什麼好說的,簡單看一下原始碼即可。

在看原始碼的過程中,通過對比hashmap和hashtable的不同點,有兩個疑問:

1. hashmap和hashtable,乙個採用(table.length - 1) & hash 計算要放置的位置,乙個採用取模的 方法,這有什麼不同嗎?為什麼要這樣做?

2. hashtable為什麼不用紅黑樹了?

通過查閱資料發現,hashtable是 jdk 1.0 就引入的類,而 hashmap 是 jdk 1.2 才引入的乙個map介面的實現,而hashtable設計的時候就採用了取模的方法計算位置,也沒有設計紅黑樹進行優化,而新增hashmap的時候選擇了不同的方法,剛開始的時候hashmap也沒有使用紅黑樹,是在 jdk 1.8 的時候才引入了紅黑樹進行優化。

看到有篇部落格寫的很好,應該是比我大一屆的學生。

hashmap是非執行緒安全的,hashtable是執行緒安全的,所以hashtable重量級一些,因為使用了synchronized關鍵字來保證執行緒安全,當乙個執行緒在使用乙個synchronized修飾的方法時,其他被synchronized修飾的方法都不能使用。

hashmap允許key和value都為null,而hashtable都不能為null。

hashtable繼承自 jdk 1.0 的 dictionary 虛擬類,而hashmap是 jdk 1.2 引進的 map 介面的乙個實現。

hashtable和hashmap擴容的方法不一樣,hashtable中陣列預設大小11,擴容方式是 old*2+1。hashmap中陣列的預設大小是16,而且一定是2的指數,增加為原來的2倍。

兩者通過hash值雜湊到hash表的演算法不一樣,hashtable是古老的除留餘數法,直接使用object的hashcode,而後者是強制容量為2的冪,重新根據hashcode計算hash值,在使用hash和(hash表長度 – 1)進行與運算,也等價取膜,但更加高效,取得的位置更加分散,偶數,奇數保證了都會分散到。前者就不能保證。

hashmap的迭代器(iterator)是fail-fast迭代器,而hashtable的enumerator迭代器不是fail-fast的。所以當有其它執行緒改變了hashmap的結構(增加或者移除元素),將會丟擲concurrentmodificationexception,但迭代器本身的remove()方法移除元素則不會丟擲concurrentmodificationexception異常。參考文章。

大致就是這些,學無止境,加油。–201703042011

原始碼解析 JDK原始碼之LinkedHashMap

linkedhashmap原始碼,基於 jdk1.6.43 他繼承了hashmap,並且實現了插入和訪問的有序功能 public class linkedhashmapextends hashmapimplements map 其也有乙個entry內部類,繼承了 hashmap 的entry 內部類...

JDK原始碼之Map

1.hashmap hashmap初始化的方式有四種。建立乙個entry陣列,預設初始長度為16,當大於0.75的時候,擴充套件為當前的2倍。有4中初始化map的方式。mapmap new hashmap mapmap2 new hashmap 17 mapmap3 new hashmap 15,2...

JDK原始碼之PriorityQueue原始碼剖析

優先佇列在程式開發中屢見不鮮,比如作業系統在進行程序排程時一種可行的演算法是使用優先佇列,當乙個新的程序被fork 出來後,首先將它放到佇列的最後,而作業系統內部的scheduler負責不斷地從這個優先佇列中取出優先順序較高的程序執行 爬蟲系統在執行時往往也需要從乙個優先順序佇列中迴圈取出高優先順序...