HashSet/HashMap存储过程、扩容、实现原理

论坛可以帮助程序员很快的提升自己

第一次看见这句话不以为然,因为多多少少逛过,感觉并没有对自己多大帮助

慢慢逛论坛次数多了,感觉自己只是在打发时间,根本对自己没有任何帮助。突发奇想不再逛首页,而是通过各大板块选自己最近学的知识来检验自己的学习。

------------------------------------------------------分割线-------------------------------------------------------

还好,发现了不错的论坛,比如

Surrin1999发出的 关于HashSet的有序无序问题

nayi_224回复的见解真的很到位,多的不说,

   

------------------------------------------------------分割线-------------------------------------------------------以下蓝色字为JDK源码

HashSet是基于HashMap存储的数据,结构是数组 + 链表

默认容量static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

加载因子(用来扩容的) static final float DEFAULT_LOAD_FACTOR = 0.75f;

在底层存储数据时,较为形象的画出如下图:

存储过程:

扩容是在当前容量的基础上增加一倍(newCap = oldCap << 1),在不超过最大容量 的前提下 static final int MAXIMUM_CAPACITY = 1 << 30;  // 1073741824

关于加载因子:

加载因子过小,会导致内存的浪费,也会导致rehash操作频繁,降低效率

加载因子过大,会导致每个桶中的链表过长从而降低效率

从JDK1.8开始,为了减小扩容次数,同时也为了保证每一个桶中的查询效率,在桶中元素超过8时(static final int TREEIFY_THRESHOLD = 8;),采取红黑树结构,

               if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st  注意下标从0开始

                       treeifyBin(tab, hash);

关于红黑树,本人比较愚笨,不懂了。。。

关于指定初始容量:

 static final int tableSizeFor(int cap) {

        int n = cap - 1;

        n |= n >>> 1;

        n |= n >>> 2;

        n |= n >>> 4;

        n |= n >>> 8;

        n |= n >>> 16;

        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ?

MAXIMUM_CAPACITY : n + 1;

 }

以上是JDK中源码,计算结果可以借助IDE进行,只需每次修改n结束后输出即可,结论是:

指定初始容量X时,并且 2n-1 < x <=2n 那么最终该集合的容量为2n。

猜你喜欢

转载自blog.csdn.net/m0_37461645/article/details/82084499
今日推荐