Map m3 = new HashMap(3); 申請了多大的數組空間

1、先看結果

        Map<String, String> m0 = new HashMap<>(0);// 不創建內部存儲數組
        m0.put("k","v");// 內部空間開闢了 1 (數組長度=1)
        Map<String, String> m1 = new HashMap<>(1);// 不創建內部存儲數組
        m1.put("k","v");// 內部空間開闢了 1 (數組長度=1)
        Map<String, String> m2 = new HashMap<>(2);// 不創建內部存儲數組
        m2.put("k","v");// 內部空間開闢了 2 (數組長度=2)
        Map<String, String> m3 = new HashMap<>(3);// 不創建內部存儲數組
        m3.put("k","v");// 內部空間開闢了 4 (數組長度=4)

首先,我們應該知道HashMap內部是用數組存儲數據的。

沒錯,下面這句話,是不創建數組的,所以結論是 0

 Map<String, String> m3 = new HashMap<>(3); 
2、爲什麼是0?

new HashMap<>(3) 只是設置了threshold(擴容閾值)和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);

        this.loadFactor = loadFactor;
        threshold = initialCapacity;
        init();
    }

3、什麼時候創建數組?

只有調用put的方法的時候才真正的創建數組,具體創建多大的數組呢?從上面的代碼可以看出m3 創建了 長度=4的數組

    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold); // 這句話會去創建數組
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        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++;
        addEntry(hash, key, value, i);
        return null;
    }

4、數組的長度爲什麼不是3?

k=數組長度-1,因爲要保證k這個值的二進制全是1,所以new HashMap(3),實際數組長度=4,這樣k=3,k的二進制值:11

如果new HashMap(5),內部數組長度=8, k=7,k的二進制:111


    private void inflateTable(int toSize) {
        // Find a power of 2 >= toSize
        int capacity = roundUpToPowerOf2(toSize); // 這句話保證了k(k=數組長度capacity-1)的二進制值全是1

        threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
        table = new Entry[capacity];
        initHashSeedAsNeeded(capacity);
    }
5、分析roundUpToPowerOf2方法

    private static int roundUpToPowerOf2(int number) {
        // assert number >= 0 : "number must be non-negative";
        return number >= MAXIMUM_CAPACITY
                ? MAXIMUM_CAPACITY
                : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
    }

p = number-1 ,然後左移一位p<<1, Integer.highestOneBit(p),獲取最高位,其他位都是0

例子:number=3,p=(二級制0010),p左移一位等於4(二級制0100),然後獲取最高位的結果是4(二級制100)

 number=6,p=5(二級制0101),p左移一位等於10(二級制1010),然後獲取最高位的結果是8(二級制1000)

這樣就可以的結果就可以保證k的二級制都是1了

6、爲什麼要保證k的二進制全是1?

    static int indexFor(int h, int length) {
        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
        return h & (length-1);
    }

因爲要根據hash 值來索引,當前數據存放在哪個下標數組裏,同時還不能越界,如上代碼,把hash和length-1 進行一下與操作,就能找到該數據存放的下標,同時還不越界。

 

分析的jdk版本jdk7_75

如有不對,請指出!謝謝




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章