多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > HashMap源碼分析及沖突處理的細節

HashMap源碼分析及沖突處理的細節

來源:程序員人生   發布時間:2015-06-15 08:01:55 閱讀次數:3068次

1.  首先看1下hashmap的數據結構,可以看到是數組加鏈表實現的。

transient Entry<K,V>[] table =(Entry<K,V>[]) EMPTY_TABLE;

可以看到它的實現是1個Entry<K,V>類型的名為table的數組。而Entry是HashMap中的1個內部類。

static class Entry<K,V> implementsMap.Entry<K,V> {

       final K key;

       V value;

       Entry<K,V> next;

       int hash;

       它有4個屬性,key,value,next,hash。由于有next屬性,所以自然會想到鏈表的結點類,事實上,當出現hash沖突時,由于HashMap使用鏈地址法來解決沖突。所以table數組的每個元素就會構成鏈表結構。所以可以說HashMap就是1個存儲鏈表的數組。

  

2.   HashMap的table數組的默許大小是16,并且大小永久是2的n次方。它還有1個負載因子,默許為0.75,可以通過帶參數的構造方法自己指定。負載因子loadFactor的作用是:HashMap中的實際的數據大小除以總容量(initialCapacity),當值到達loadFactor時,HashMap的總容量自動擴大1倍。

  staticfinal int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

static final float DEFAULT_LOAD_FACTOR = 0.75f;

 

   計算threshold,值為capacity *loadFactor。

threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY +1);

 

   這里就會判斷,當size的值大于threshold(即capacity *loadFactor)時,就會進行擴容。

if ((size >= threshold) && (null != table[bucketIndex])){

            resize(2 * table.length);

 

 

3.接下來以put方法作為入口,進行分析。

1.首先進行hash運算,并求出將要存入的數組下標。

int hash = hash(key);

int i = indexFor(hash, table.length);

 

     接下來看看計算下標的算法是如何實現的。進入到indexFor方法中,實現的代碼以下:

static int indexFor(int h, int length) {

        // assertInteger.bitCount(length) == 1 : "length must be a non-zero power of2";

        return h &(length⑴);

    }

 

    具體是h &(length⑴),這樣計算的值介于0和length⑴之間,有點類似于hash%length 的求模運算。之所以用&運算我認為是位運算的效力更高吧。

 

2.然后是下面這段代碼:

 

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);

                returnoldValue;

            }

        }

 

        modCount++;

        addEntry(hash, key,value, i);

 

 

        會判斷table[i]是不是為null,這是會出現兩種情況,先分析第1種情況,即table[i]還沒有元素,是null的情況,這時候循環就沒有履行,繼續往下,去履行addEntry方法。addEntry方法中先進行判斷是不是需要擴容,如果需要,就進行擴容。然后又進入到createEntry方法中。它的代碼實現以下:

 

void createEntry(int hash, K key, V value, int bucketIndex) {

        Entry<K,V> e =table[bucketIndex];

        table[bucketIndex] =new Entry<>(hash, key, value, e);

        size++;

    }

 

        它做的工作就是把hash,key, value, e4個屬性組裝成1個Entry的對象e,并將它放在數組下標相應的位置,這時候如果加入的是第1個元素,e則為null,所以next指向了null。最后再把size加1.

 

        下面分析第2種情況,即即table[i]已有了元素,不是null的情況。這時候會履行上面的那1段for循環,這個循環的作用就是順次遍歷全部table[i]鏈表,并且判斷這個鏈表的每個元素的key是不是和新加進來的元素的key相同,如果相同新的value就會覆蓋舊的value,即保證HashMap中唯1的key有唯1的value.

         進行完了覆蓋的操作后,就會履行剩下的代碼,和第1種情況1樣,履行addEntry方法。addEntry方法中先進行判斷是不是需要擴容,如果需要,就進行擴容。再履行createEntry方法。這時候e = table[bucketIndex];計算出來的e就不為null了,為原來的i下標處的元素。然后又封裝1個新的Entry對象,放入到table[i]位置,它的next指向了e,即原來的table[i]處的元素。

        所以通過分析我們可以發現,最后放入的元素總是在這個沖突鏈表的表頭的位置。

        最后,可以看到,當出現沖突時,會把數據放入鏈表中,每次插入新的元素都會對全部鏈表進行遍歷操作,影響程序的效力。所以當我們向HasnMap中放入的key的數據類型是自定義類型的時候,要依照規范公道的實現hashcode和equals方法,盡可能避免沖突。另外,由于它的底層實現也是數組,所以也要盡可能避免擴容。最好能估算出初始的大小,而對負載因子,聽說0.75是計算出的最好值,所以還是用默許的吧。

 

 

 

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 最近高清中文字幕在线国语5 | 久爱免费精品视频在线播放 | 最新日本免费一区二区三区中文 | 欧美黑人乱大交ⅹxxxxx | 国产在线a不卡免费视频 | 在线视频国产一区 | 中文字幕中韩乱码亚洲大片 | 国产精品亚洲综合网站 | 一级坐爱 | 欧美一区三区 | 亚洲第一视频区 | 欧美性猛交xxxx乱大交蜜桃 | www.91视频.com| 一区二区三区精品 | 亚洲 欧美 小说 国产 图片 | 最近中文字幕版免费 | 欧美黑人性xxx猛交 欧美黑人性猛交 | 亚洲国产成人精品一区二区三区 | jizzzz日本| 亚洲视频中文字幕在线 | 天码毛片一区二区三区入口 | 亚洲a视频在线 | 亚洲一区二区三区四区五区六区 | 欧美一区二区三区成人看不卡 | aa黄色片| 欧美高清另类videosbestsex | 综合色在线观看 | 国产精品新婚门 | 国产福利不卡视频在免费 | 久久久日本精品一区二区三区 | 欧美精品福利 | 亚洲人和日本人jzz护士 | 国产精品久久久精品三级 | 美女无遮挡免费视频观看网站 | 中文字幕之中文字幕 | 国产亚洲第一 | 中文字幕视频网 | 黄色网址免费观看 | 在线午夜视频 | 亚洲色图第1页 | 久草在线香蕉 |