jdk1 7 hashMap原始碼學習

2021-10-07 13:01:23 字數 4147 閱讀 1387

//預設初始化長度

static final int default_initial_capacity = 16;

//最大長度

static final int maximum_capacity = 1 << 30;

//預設載入因子 size/capacity = loadfactor

static final float default_load_factor = 0.75f;

//放元素的陣列 要求長度是2的n次冪

transient entry table;

//已經放入的元素的個數

transient int size;

// capacity * load factor

int threshold;

//載入因子

final float loadfactor;

//map被改變的次數

transient int modcount;

構造器引數都是圍繞capacity(陣列長度)和loadfactor(載入因子)

public

hashmap

(int initialcapacity,

float loadfactor)

public

hashmap

(int initialcapacity)

public

hashmap()

public

hashmap

(map<

?extendsk,

?extends

v> m)

hash

這個方法是用來獲取加入進來的鍵值對  key的hash值
final

inthash

(object k)

// 預設為0

h = hashseed;

}//這三步獲取key的hash值

//為什麼要重新計算hashcode值,而不是將它直接去取模

// 因為length太小了,導致hashcode只有低位參與運算

// 而將它右移,讓高位參與到運算,減少碰撞概率

h ^= k.

hashcode()

; h ^=

(h >>>20)

^(h >>>12)

;return h ^

(h >>>7)

^(h >>>4)

;}

indexfor

用來獲取鍵值對    即將放入陣列的哪乙個下標
static

intindexfor

(int h,

int length)

get

public v get

(object key)

final entry

getentry

(object key)

return null;

}

put

public v put

(k key, v value)

}// 修改次數+1

modcount++

;// 如果之前map中沒有該key,新增乙個鍵值對

addentry

(hash, key, value, i)

;return null;

}void

addentry

(int hash, k key, v value,

int bucketindex)

// 建立新的鍵值對

createentry

(hash, key, value, bucketindex);}

void

createentry

(int hash, k key, v value,

int bucketindex)

resize

單獨看這個擴容方法,是因為多執行緒環境操作該方法,擴容後的陣列,可能會有乙個迴圈鍊錶

即 a ⇄ b -> null, 這樣的後果是遍歷該鍊錶時,會死迴圈

void

resize

(int newcapacity)

// 建立乙個新的陣列

entry[

] newtable =

newentry

[newcapacity]

;boolean oldalthashing = usealthashing;

usealthashing |= sun.misc.vm.

isbooted()

&&(newcapacity >= holder.alternative_hashing_threshold)

;// 在沒有特殊情況下,rehash還是false

boolean rehash = oldalthashing ^ usealthashing;

transfer

(newtable, rehash)

; table = newtable;

threshold =

(int

)math.

min(newcapacity * loadfactor, maximum_capacity +1)

;}void

transfer

(entry[

] newtable,

boolean rehash)

int i =

indexfor

(e.hash, newcapacity)

; e.next = newtable[i]

; newtable[i]

= e;

e = next;}}

} 假如有一條鍊錶是這樣的,裡面有2個節點物件

entry

a =

> entry

b a.key = a b.key = b

a.value = a b.value = b

a.next = b b.next = null

1.x執行緒執行到關鍵位置停止,切換到y執行緒。x中next = e.next = b。

2.y執行緒執行完transfer方法停止,切換回x執行緒,此時節點a,b物件已經發生變化

假如新的table中它們還是在乙個下標位置上,那麼此時

b.next = a , a.next = null; b =

> a =

> null

3.x執行緒繼續執行,第一次迴圈,此時x執行緒中的newtable中還沒有值

e.next = a.next = newtable[i]

= null

newtable[i]

= e = a (此時a是head 鍊錶是 a =

>null)

e = next = b

4.第二次迴圈

next = b.next = a (因為y執行緒,b物件發生變化,如果沒被修改應該是null)

e.next = b.next = newtable[i]

(head)

= a newtable[i]

= b (此時b變為head)

e = next = a

正常情況下 e = null, 這裡就結束了

5.第三次迴圈

next = a.next = null

e.next = a.next = newtable[i]

(head)

= b newtable[i]

= a e = next = null

結束 此時鍊錶變成 a ⇄ b

JDK1 7HashMap原始碼解析

hashmap已經看了很多篇文章了,今天還是自己解析一遍吧。我先大致介紹下hashmap的內部結構再跟著原始碼解讀一番 眾所周知hashmap的內部就是乙個雜湊表 什麼是雜湊表?如果我們利用陣列可隨機訪問的特性,將要存入的鍵通過一種雜湊演算法轉換成乙個數字,並把這個數字轉換成陣列的下標,然後將鍵和他...

JDK1 7 HashMap原始碼解析

在jdk1.7中,hashmap底層資料結構是由陣列和鍊錶構成,陣列存放entry物件,而entry物件是對鍊錶頭部第乙個元素的引用。arraylist中add方法是通過下標的累加進行資料的插入,hashmap則不同。hashmap通過獲取key的hashcode值,而hashmap中構成其陣列的預...

JDK1 7的HashMap原始碼解讀

default initial capacity 初始化容量,中為1 4 即為16。為什麼要這樣寫呢?maximum capacity 最大容量,中衛1 30 即為2的30次冪。30次冪的原因是 改屬性為int型別,int型別最大為4個位元組,共32個二進位制位,理論上可以向左移動31次,即31次冪...