原始碼解析 JDK原始碼之LinkedHashMap

2021-07-30 08:59:14 字數 4110 閱讀 1584

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...