国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

jdk7中HashMap知識點整理

AJie / 1152人閱讀

摘要:再最壞的情況下,鏈表查找的時間復(fù)雜度為而紅黑樹一直是這樣會提高的效率。中的中定義了一個變量,當(dāng)節(jié)點個數(shù)時,將采用紅黑樹存儲參考資料和的區(qū)別和的區(qū)別

HashMap中的幾個重要變量
默認(rèn)初始容量,必須是2的n次方 
static final int DEFAULT_INITIAL_CAPACITY = 16;

最大容量,當(dāng)通過構(gòu)造方法傳入的容量比它還大時,就用這個最大容量,必須是2的n次方
static final int MAXIMUM_CAPACITY = 1 << 30;

默認(rèn)負(fù)載因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;

用來存儲鍵值對,可以看到鍵值對都是存儲在Entry中的
transient Entry[] table;

//capacity * load factor,超過這個數(shù)就會進(jìn)行再哈希
int threshold;

HashMap中的元素是用名為tableEntry數(shù)組來保存的,默認(rèn)大小是16

capacity:數(shù)組的容量
load_factor:負(fù)載因子
threshold:實際能承載的容量,等于上面兩個相乘,當(dāng)size大于threshold時,就會進(jìn)行rehash

jdk7中在面對key為String的時候采用了區(qū)別對待,會有alternative hashing,但是這個在jdk8中已經(jīng)被刪除了

存儲結(jié)構(gòu)

Entry是一個鏈表結(jié)構(gòu),不僅包含keyvalue,還有可以指向下一個的next

static class Entry implements Map.Entry {
        final K key;
        V value;
        Entry next;
        int hash;

        /**
         * Creates new entry.
         */
        Entry(int h, K k, V v, Entry n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }
        ...
put方法
public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry 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++;
        addEntry(hash, key, value, i);
        return null;
    }

首先通過hash方法對hashcode進(jìn)行處理:

final int hash(Object k) {
        int h = 0;
        h ^= k.hashCode();

        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

可以看到只是在keyhashcode值上做了一些處理,通過hash計算出來的值將會使用indexFor方法找到它應(yīng)該所在的table下標(biāo):

static int indexFor(int h, int length) {
        return h & (length-1);
    }

這個方法其實相當(dāng)于對table.length取模。

當(dāng)需要插入的keynull時,調(diào)用putForNullKey方法處理:

 private V putForNullKey(V value) {
        for (Entry e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }

putForNullKey方法只從table[0]這個位置開始遍歷,因為keynull只放在table中的第一個位置,下標(biāo)為0,在遍歷中如果發(fā)現(xiàn)已經(jīng)有keynull了,則替換新value,返回舊value,結(jié)束;如果還沒有keynull,調(diào)用addEntry方法增加一個Entry:

void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }

可以看到j(luò)dk7中resize的條件已經(jīng)發(fā)生改變了,只有當(dāng) size>=threshold并且 table中的那個槽中已經(jīng)有Entry時,才會發(fā)生resize。即有可能雖然size>=threshold,但是必須等到每個槽都至少有一個Entry時,才會擴容。還有注意每次resize都會擴大一倍容量

void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }

最后看createEntry,它先保存這個桶中的第一個Entry,創(chuàng)建新的Entry放入第一個位置,將原來的Entry接在后面。這里采用的是頭插法插入元素。

get方法

其實get方法和put方法如出一轍,怎么放的怎么拿

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        Entry entry = getEntry(key);

        return null == entry ? null : entry.getValue();
    }

key為null時,還是去table[0]去取:

private V getForNullKey() {
        for (Entry e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }

否則調(diào)用getEntry方法:

final Entry getEntry(Object key) {
        int hash = (key == null) ? 0 : hash(key);
        for (Entry 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;
    }

這個方法也是通過key的hashcode計算出它應(yīng)該所在的下標(biāo),再遍歷這個下標(biāo)的Entry鏈,如果key的內(nèi)存地址相等(即同一個引用)或者equals相等,則說明找到了

hash的原則

A、等冪性。不管執(zhí)行多少次獲取Hash值的操作,只要對象不變,那么Hash值是固定的。如果第一次取跟第N次取不一樣,那就用起來很麻煩.

B、對等性。若兩個對象equal方法返回為true,則其hash值也應(yīng)該是一樣的。舉例說明:若你將objA作為key存入HashMap中,然后new了一個objB。在你看來objB和objA是一個東西(因為他們equal),但是使用objB到hashMap中卻取不出來東西。

C、互異性。若兩個對象equal方法返回為false,hash值有可能相同,但最好是不同的,這個不是必須的,只是這樣做會提高h(yuǎn)ash類操作的性能(碰撞幾率低)。

解決hash碰撞的方法:
開放地址法
鏈地址法

hashmap采用的就是鏈地址法,這種方法好處是無堆積現(xiàn)象,但是next指針會占用額外空間

和jdk8中的HashMap區(qū)別

在jdk8中,仍然會根據(jù)key.hashCode()計算出hash值,再通過這個hash值去定位這個key,但是不同的是,當(dāng)發(fā)生沖突時,會采用鏈表和紅黑樹兩種方法去處理,當(dāng)結(jié)點個數(shù)較少時用鏈表(用Node存儲),個數(shù)較多時用紅黑樹(用TreeNode存儲),同時結(jié)點也不叫Entry了,而是分成了Node和TreeNode。再最壞的情況下,鏈表查找的時間復(fù)雜度為O(n),而紅黑樹一直是O(logn),這樣會提高HashMap的效率。
jdk8中的HashMap中定義了一個變量TREEIFY_THRESHOLD,當(dāng)節(jié)點個數(shù)>= TREEIFY_THRESHOLD - 1時,HashMap將采用紅黑樹存儲

參考資料:jdk8 HashMap

和Hashtable的區(qū)別

Hashtable 和 HashMap的區(qū)別

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/64464.html

相關(guān)文章

  • 《阿里巴巴 Java開發(fā)手冊》讀后感

    摘要:回到家才發(fā)現(xiàn)當(dāng)時買了一堆書,這堆書還有沒撕包裝的呢于是我翻出了最薄的一本阿里巴巴開發(fā)手冊這本書一共就多頁,一天就可以通讀完了,看完之后我又來水博文了。為了保證單元測試穩(wěn)定可靠且便于維護,單元測試之間不能互相調(diào)用,也不能依賴執(zhí)行的先后順序。 前言 只有光頭才能變強 前一陣子一直在學(xué)Redis,結(jié)果在黃金段位被虐了,暫時升不了段位了,每天都拿不到首勝(好煩)。 趁著學(xué)校校運會,合理地給自己...

    young.li 評論0 收藏0
  • Java--JDK7與JDK8的HashMap的區(qū)別

    摘要:簡介本文介紹與的的區(qū)別。復(fù)雜度數(shù)組鏈表紅黑樹鏈表節(jié)點數(shù)大于時,鏈表轉(zhuǎn)為紅黑樹,復(fù)雜度降至插入位置插入鏈表頭部插入鏈表尾部算法復(fù)雜簡單。紅黑樹效率高,提高查詢效率的地方由紅黑樹實現(xiàn),沒必要像那么復(fù)雜。 ??簡介? ? ? ? 本文介紹JDK7與JDK8的HashMap的區(qū)別。JDK7與...

    姘存按 評論0 收藏0
  • Java經(jīng)典

    摘要:請注意,我們在聊聊單元測試遇到問題多思考多查閱多驗證,方能有所得,再勤快點樂于分享,才能寫出好文章。單元測試是指對軟件中的最小可測試單元進(jìn)行檢查和驗證。 JAVA容器-自問自答學(xué)HashMap 這次我和大家一起學(xué)習(xí)HashMap,HashMap我們在工作中經(jīng)常會使用,而且面試中也很頻繁會問到,因為它里面蘊含著很多知識點,可以很好的考察個人基礎(chǔ)。但一個這么重要的東西,我為什么沒有在一開始...

    xcold 評論0 收藏0
  • 深入分析——HashSet是否真的無序?(JDK8)

    摘要:但是,如果像上例中只取最后幾位的時候,這可不是什么好事,即使我的數(shù)據(jù)分布很散亂,但是哈希沖突仍然會很嚴(yán)重。由于我們所創(chuàng)建的是類型的,這也是最巧的一點,類型的返回值就是其值本身,而存儲的時候元素通過一些運算后會得出自己在數(shù)組中所處的位置。 HashSet 是否無序 (一) 問題起因: 《Core Java Volume I—Fundamentals》中對HashSet的描述是這樣的: H...

    everfight 評論0 收藏0
  • 前百度面試官整理的——Java后端面試題(一)

    摘要:發(fā)生了線程不安全情況。本來在中,發(fā)生哈希沖突是可以用鏈表法或者紅黑樹來解決的,但是在多線程中,可能就直接給覆蓋了。中,當(dāng)同一個值上元素的鏈表節(jié)點數(shù)不小于時,將不再以單鏈表的形式存儲了,會被調(diào)整成一顆紅黑樹。 showImg(https://segmentfault.com/img/bVbsVLk?w=288&h=226); List 和 Set 的區(qū)別 List , Set 都是繼承自...

    JessYanCoding 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<