论坛可以帮助程序员很快的提升自己,
第一次看见这句话不以为然,因为多多少少逛过,感觉并没有对自己多大帮助
慢慢逛论坛次数多了,感觉自己只是在打发时间,根本对自己没有任何帮助。突发奇想不再逛首页,而是通过各大板块选自己最近学的知识来检验自己的学习。
------------------------------------------------------分割线-------------------------------------------------------
还好,发现了不错的论坛,比如
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。