linkedhashmap原始碼,基於
jdk1.6.43
他繼承了hashmap,並且實現了插入和訪問的有序功能
public class linkedhashmapextends hashmapimplements map
其也有乙個entry內部類,繼承了
hashmap
的entry
內部類,但是增加了兩個屬性
before
、after
。原始碼對這兩個屬性的注釋含義是這兩個域包含兩個鍊錶用於迭代。
private static class entryextends hashmap.entry// these fields comprise the doubly linked list used for iteration.
entrybefore, after;
**中的乙個屬性header,是雙向鍊錶的頭指標。由此我們推斷,
linkedhashmap
的內部實現是在
hashmap
的基礎上增加了乙個額外的雙向鍊錶,用於儲存資料的插入順序。
private transient entryheader;
布林型別變數,如果為true的話則按訪問順序排序,如果為
false
的話則按插入順序排序。
private final boolean accessorder;
下面的幾個構造方法都直接呼叫了父類的構造方法,只是呼叫的引數各不相同,但是共同點是都將accessorder設定為
false
。
public linkedhashmap(int initialcapacity, float loadfactor)
public linkedhashmap(int initialcapacity)
public linkedhashmap()
public linkedhashmap(map<? extends k, ? extends v> m)
下面的構造方法有所不同,可以傳入accessorder,即可以在構造時改變
accessorder
的值。
public linkedhashmap(int initialcapacity, float loadfactor, boolean accessorder)
下面的init方法覆蓋了父類的
init
方法,我們分析
hashmap
原始碼時了解到在構造的最後會呼叫
init
方法,預設的
init
方法實現為空,其目的是交由子類進行各自的處理,其在
linkedhashmap
中發揮了重要的作用。下面的**含義就是在構造完成後,初始化頭指標,並根據雙向鍊錶的特性將頭指標的前後指標都指向自己本身,實現雙向鏈結的初始化操作。
void init()
下面是上面的init方法呼叫的本身
entry
內部類的構造器,傳入的分別是
hash
值、key
值、value
值和hashmap
中需要指向陣列後繼元素的
next
指標變數。我們看到頭指標初始化的
hash
值為-1
作為標誌位。
entry(int hash, k key, v value, hashmap.entrynext)
重寫了父類的transfer方法,該方法的目的是在
map的陣列擴容時,重新指定每乙個元素的位置,但是其實現與
hashmap
不同,hashmap
的實現是遍歷整個陣列,對於每個陣列元素的單鏈表重新計算位置,但是
linkedhashmap
並沒有直接採用父類的方法,而是遍歷了每個元素的前後指標,我們知道鍊錶的遍歷速度比陣列快一些,所以這種實現是乙個很高效率的實現。
void transfer(hashmap.entry newtable)
}
下面的方法也覆蓋了父類的方法重新實現,目的也是為了更快的實現遍歷。
public boolean containsvalue(object value)
呼叫父類的clear方法,並將頭指標的前後指標重置為
header。
public void clear()
下面的方法使用protected修飾,明顯就是為了讓子類進行後續的修改,且目前的實現中一直返回
false。
protected boolean removeeldestentry(map.entryeldest)
下面的方法比較重要,linkedhashmap中沒有覆蓋父類的
put方法,但是他是如何來維護鍊錶的順序呢?關鍵就是下面的
addentry
方法,這個
addentry
根據hashmap
中的put
函式中的**可知他會在
put方法的最後被呼叫。
hashmap
的addentry
方法中直接放置新加入元素的位置,然後決定是否擴充陣列的大小。但是
linkedhashmap
的addentry
方法中,在判斷是否擴充陣列前呼叫了
createentry
方法,來實現維護鍊錶順序。這個方法在
createentry
之後進行了一步判斷
removeeldestentry
,從上面的**可以看到這個方法目前是
false
,就會走
else
的分支。
if這個分支中的操作其實會刪除最先插入的元素。但是實際在
linkedhashmap
中並沒有使用。
void addentry(int hash, k key, v value, int bucketindex) else
}
下面就是createentry方法
void createentry(int hash, k key, v value, int bucketindex)
這個get方法覆蓋了父類的
get方法,其目的是為了呼叫
e.recordaccess(this);
這一行**。
public v get(object key)
上面那一行**的意義如下,根據accessorder的設定來修改雙向鍊錶的順序,以實現根據訪問來排序雙向鍊錶。
void recordaccess(hashmapm)
}
還有乙個remove方法定義在
entry
內部,用於刪除元素,
linkedhashmap
中沒有remove
方法,所以
remove
方法的呼叫其實是呼叫父類的方法,但是
hashmap
的remove
方法在結尾呼叫了
entry
的recordremoval
方法,而
linkedhashmap
在重寫recordremoval
方法時呼叫了其
entry
的remove
方法,最終實現了在刪除元素時對自身鍊錶的操作,從鍊錶中刪除元素並改變指標的指向。
private void remove()
void recordremoval(hashmapm)
JDk原始碼解析之四 Vector原始碼解析
具體的三個屬性 解釋看圖中注釋。vector沒有採取arraylist臨界值擴容的辦法,而是每次不夠的時候,直接根據capacity的值來增加。具體怎麼增加後面會說。vector的構造方法如下。簡單粗暴,如果呼叫無參建構函式,直接就將初始容量設定成了10,最終在右側的構造方法裡,將陣列的長度設定為1...
JDK原始碼解析 ThreadLocal
說明 本文是jdk 1.8版本 1.簡介 threadlocal 又叫做執行緒本地變數,也被稱為執行緒本地儲存。threadlocal 為 變數 在每乙個執行緒中建立 乙個 副本 不是原來變數的引用 每乙個執行緒都會獨自擁有變數副本,而不會相互影響。2.實現方式 1 set 方法,因為執行緒thre...
JDK原始碼解析 StringBuilder
stringbuilder和stringbuffer一樣,都是繼承自抽象類abstractstringbuilder類,也是乙個可變的字串行。stringbuilder和stringbuffer非常相似,甚至有互相相容的api,不過,stringbuilder不是執行緒安全的,這是和stringbu...