欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解HashMap各個方法的源碼

 更新時間:2023年12月02日 09:22:30   作者:nuomizhende45  
這篇文章主要介紹了深入理解HashMap各個方法的源碼,HashMap初始容量不能為負數(shù),若初始容量大于最大容量,則讓它等于最大容量,負載因子必須大于0,并且傳入的initialCapacity不是HashMap的容量大小,需要的朋友可以參考下

HashMap各個方法的源碼

put方法

首先分析第一個比較重要的方法 put 方法,源碼如下

public V put(K key, V value) {
if (key == null)
return putForNullKey(value);  //這里判斷key是否為空,若為空則調(diào)用putForNullKey處理null值
int hash = hash(key); //根據(jù)key的hashCode計算hash值
int i = indexFor(hash, table.length);//搜索該key的hash值在table中的索引,其中table是當HashMap用于存放entry的一個數(shù)組
//這里循環(huán)遍歷table中對應該索引的entry,若發(fā)現(xiàn)存在key與put進來的key相同則覆蓋其value值
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
//將key value 添加到 索引i處
addEntry(hash, key, value, i);
return null;
}

分析上面的源碼,我們可以得到下面的結論:

當我們試圖將一個key-value 調(diào)用put方法放入HashMap的時候,首先會調(diào)用key的hashCode方法算出該Entry存放的位置,若兩個key的hashCode相同則在table中的存儲位置相同,則先調(diào)用equals方法判斷兩個key是否相同,相同則覆蓋,不相同則產(chǎn)生一個Entry鏈表(因為table數(shù)組中一個索引位置只能放入一個Entry,所以當有多個key的hashCode相同時,這些key就會以鏈表的形式存在,并且最后put進來的key在鏈表的最前面)

構造方法

然后則是HashMap的構造方法,這里以 HashMap(int initialCapacity, float loadFactor)這個構造器為例,源碼如下

public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.loadFactor = loadFactor;
threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
table = new Entry[capacity];
useAltHashing = sun.misc.VM.isBooted() &&
(capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
init();
}

從上面的源碼可以看出 ,初始容量不能為負數(shù),若初始容量大于最大容量,則讓它等于最大容量,負載因子必須大于0,并且傳入的initialCapacity不是HashMap的容量大小,

實際容量大小的計算規(guī)則是大于傳入的initialCapacity的最小的2的n次方,比如傳入的initialCapacity是5 那么實際容量則是8 因為2的3次方大于5。

get方法

下面再分析一下HashMap的存儲性能,下面的 get方法的源碼

public V get(Object key) {
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}

再次強調(diào)一下table的概念,table就是當我們初始化一個HashMap時,會自動創(chuàng)建一個長度為capacity的Entry數(shù)組,我們把這個數(shù)組存放元素的位置叫“桶”,并且每個桶只存儲一個Entry元素(也就是我們的鍵值對),并且當我們put一個鍵值對時,先計算key的hashCode來判斷這個鍵值對會放入哪一個桶,所以若多個key的hashCode相同時,他們都要被放入一個桶里面,但是一個桶里面只能放入一個Entry(鍵值對),要解決這個問題先看下面的代碼

Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}

這是Entry的構造方法,我們可以看出Entry對象包含一個Entry的引用,用來指向下一個Entry,這樣就解決了hashCode相同,存放沖突的問題,所以當有多個key的hashCode相同時,就會形成一個Entry鏈,我們從get方法可以看出當系統(tǒng)通過key的hashCode找到了對應的桶的時候,會遍歷這個Entry鏈,來找到我們要取的value的key

這個時候,若剛好這個Entry在鏈表的末端(也就是我們最開始put進去的Entry)那么當這個鏈表太長了,勢必會影響我們的查詢性能,這個時候就引出了loadFactor(負載因子的說法),HashMap的默認附在因子是0.75

我對負載因子的理解就是,表示HashMap在什么時候擴容,也就是說若我們初始的HashMap容量是16 負載因子是0.75

那么當有12個“桶”有了Entry時,HashMap就會擴容,并且擴大的容量是原來容量的2倍,為什么是12呢?因為0.75x16=12。

并且負載因子是可以更改的,修改它的前提是如果內(nèi)存比較緊張就可以適當?shù)脑黾迂撦d因子

若空間,內(nèi)存比較充足,更關注查詢效率則減少負載因子。為什么會這樣呢?因為若負載因子減少了,比如說減少到了0.5,默認HashMap容量大小還是16

那么當我有8個"桶"中存放了Entry數(shù)組時我就會擴容了,該桶里的Entry鏈相比于之前就不會那么長,從而提升了查詢性能。

到此這篇關于深入理解HashMap各個方法的源碼的文章就介紹到這了,更多相關HashMap方法的源碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • mybatis spring配置SqlSessionTemplate的使用方式

    mybatis spring配置SqlSessionTemplate的使用方式

    這篇文章主要介紹了mybatis spring配置SqlSessionTemplate的使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Dubbo在Spring和Spring Boot中的使用詳解

    Dubbo在Spring和Spring Boot中的使用詳解

    這篇文章主要介紹了Dubbo在Spring和Spring Boot中的使用詳解,需要的朋友可以參考下
    2017-10-10
  • SpringBoot整合RabbitMQ消息隊列的完整步驟

    SpringBoot整合RabbitMQ消息隊列的完整步驟

    這篇文章主要給大家介紹了關于SpringBoot整合RabbitMQ消息隊列的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05
  • AsyncConfigurerSupport自定義異步線程池處理異常

    AsyncConfigurerSupport自定義異步線程池處理異常

    這篇文章主要為大家介紹了AsyncConfigurerSupport自定義異步線程池處理異常詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • Springboot整合Freemarker的實現(xiàn)詳細過程

    Springboot整合Freemarker的實現(xiàn)詳細過程

    這篇文章主要介紹了Springboot整合Freemarker的實現(xiàn)詳細過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • Java工廠模式之簡單工廠,工廠方法,抽象工廠模式詳解

    Java工廠模式之簡單工廠,工廠方法,抽象工廠模式詳解

    這篇文章主要為大家詳細介紹了Java工廠模式之簡單工廠、工廠方法、抽象工廠模式,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Java數(shù)據(jù)結構常見幾大排序梳理

    Java數(shù)據(jù)結構常見幾大排序梳理

    Java常見的排序算法有:直接插入排序、希爾排序、選擇排序、冒泡排序、歸并排序、快速排序、堆排序等。本文詳解介紹它們的實現(xiàn)以及圖解,需要的可以參考一下
    2022-03-03
  • Java 全面系統(tǒng)介紹反射的運用

    Java 全面系統(tǒng)介紹反射的運用

    準備入手學習java的安全了,感覺這也是一個大的趨勢,想著盡早進入到java安全的探索中,在反序列化鏈的學習之前,需要先學習反射,不多說了,開干吧
    2022-03-03
  • Struts2學習教程之入門小白的開始基礎

    Struts2學習教程之入門小白的開始基礎

    struts2其實就是為我們封裝了servlet,簡化了jsp跳轉的復雜操作,并且提供了易于編寫的標簽,可以快速開發(fā)view層的代碼。下面這篇文章主要給各位想要學習Struts2的小白們詳細介紹了關于Struts2入門的一些開始基礎,需要的朋友可以參考下
    2018-04-04
  • 詳解java代碼中init method和destroy method的三種使用方式

    詳解java代碼中init method和destroy method的三種使用方式

    這篇文章主要介紹了詳解java代碼中init method和destroy method的三種使用方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03

最新評論