hashmap在日常工作中使用場景非常多,程式設計師都知道是hashmap是執行緒非安全的,但是底層是以什麼方式儲存的?本人仔細研讀了一下原始碼,也只是掌握了核心的儲存功能,並沒有把全部**看明白,但是對於理解hashmap的儲存結構完全夠了。
儲存結構
hashmap底層是以陣列方式進行儲存。將key-value對作為陣列中的乙個元素進行儲存。
key-value都是map.entry中的屬性。其中將key的值進行hash之後進行儲存,即每乙個key都是計算hash值,然後再儲存。每乙個hash值對應乙個陣列下標,陣列下標是根據hash值和陣列長度計算得來。
由於不能的key有可能hash值相同,即該位置的陣列中的元素出現兩個,對於這種情況,hashmap採用鍊錶形式進行儲存。
下圖描述了hashmap的儲存結構圖
entry結構分析
entry是hashmap中封裝key-value鍵值對的,主要包括如下屬性
static
class entryimplements map.entry
public
final
k getkey
() public
final
v getvalue
() // 同乙個key時,新值替換舊值,返回舊值
public
final
v setvalue
(v newvalue)
// key值重寫equals方法
public
final
boolean
equals
(object o)
return
false
; }
// 重寫hashcode值
public
final
inthashcode
() public
final
string tostring
() // 其他方法省略
}
hashmap屬性分析hashmap的屬性分析
public class
hashmap
,v>
extends
abstractmapimplements map, cloneable, serializable
; /**
* 最開始時,hashmap是乙個空陣列。
*/transient entry table = (entry) empty_table;
/*** map的元素的個數
*/transient int size;
/** hashmap的實際儲存空間大小。這個空間是總空間*載入因子得出的大小。
* 比如預設是16,載入因子是0.74。則threshold就是12。
*/int threshold;
/*** 載入因子,即使用空間達到總空間的0.75時,需要擴容。
*/final
float loadfactor;
/***
*/transient int modcount;
/*** threshold這個值的最大值就是integer.max_value
*/static final
int alternative_hashing_threshold_default = integer.max_value;
put方法put(key,value)方法是hashmap中最重要的方法,使用hashmap最主要的就是使用put,get兩個方法。put方法底層儲存又是什麼呢,我們可以從put方法的原始碼進行分析
public
v put
(k key, v value)
// 如果key為null,則將null放入元素的第乙個位置
if(key == null
) return
putfornullkey(value);
// 計算key的hash值
inthash = hash(key);
// 根據key的hash值,陣列長度計算該entry的陣列下標
inti = indexfor(hash, table.length);
/****如果當前key的已經存在於map中,則將新值替換成舊值。
**/for
(entrye = table[i]; e != null
; e = e.next)
}// 如果是新的key需要儲存,則增加操作次數modcount++
modcount++;
// 將新增key-value鍵值對新增中map中。
addentry(hash, key, value, i);
return
null
; }
addentry方法addentry方法是將新增的key-value鍵值對存入到map中。該方法主要完成兩個功能:
1.1. 新增新元素前, 判斷是否需要對map的陣列進行擴容,如果需要擴容,則擴容空間大小是多少?
1.2. 對於新增key-value鍵值對,如果key的hash值相同,則構造單向列表。
從原始碼分析結果如下:
/**
** hash:key的hash值
** key:儲存的鍵
** value:儲存的value物件值
*** bucketindex:陣列下標位置,即key-value在陣列中的位置。
**/void
addentry(int
hash, k key, v value, int
bucketindex)
// 往陣列中新增新的key-value鍵值對
createentry(hash, key, value, bucketindex);
}
createentry該方法主要完成兩個功能,第一是新增新的key到entry陣列中,第二就是對於不同key的hash值相同的情況下,在同乙個陣列下標處,構建單向鍊錶進行儲存。
void
createentry(int
hash, k key, v value
, int
bucketindex)
HashMap的實現原理
一。hashmap的資料結構 資料結構中有陣列和鍊錶來實現對資料的儲存,但這兩者基本上是兩個極端。陣列 陣列儲存區間是連續的,占用記憶體嚴重,故空間複雜的很大。但陣列的二分查詢時間複雜度小,為o 1 陣列的特點是 定址容易,插入和刪除困難 鍊錶 鍊錶儲存區間離散,占用記憶體比較寬鬆,故空間複雜度很小...
HashMap實現原理
hashmap 的get 方法 呼叫get方法返回entry public v get object key getentry方法 final entrygetentry object key 對key int hash key null 0 hash key for entrye table in...
HashMap實現原理
資料結構中有陣列和鍊錶來實現對資料的儲存,但這兩者基本上是兩個極端。陣列儲存區間是連續的,占用記憶體嚴重,故空間複雜的很大。但陣列的二分查詢時間複雜度小,為o 1 陣列的特點是 定址容易,插入和刪除困難 鍊錶儲存區間離散,占用記憶體比較寬鬆,故空間複雜度很小,但時間複雜度很大,達o n 鍊錶的特點是...