Map<String, String> m3 = new HashMap<>(3); 申请了多大的数组空间


声明:本文转载自https://my.oschina.net/huangy/blog/1615680,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

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

如有不对,请指出!谢谢

本文发表于2018年01月30日 22:32
(c)注:本文转载自https://my.oschina.net/huangy/blog/1615680,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 3550 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

万稳万当,不如一默。任何一句话,你不说出来便是那句话的主人,你说了出来,便是那句话的奴隶。

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1