-
HashSet
底层是HashMap
,第一次添加时,table数组扩容到16,临界值(threshold)是16加载因子(loadFactor
)是0.75 = 12* -
如果table数组使用到了临界值12(应该是大于12),就会扩容到16×2 = 32,新的临界值就是32 × 0.75 = 24,依次类推
-
在
Java8
中,如果一条链表的元素个数到达TREEIFY_THRESHOLD
(默认是8).并且table的大小>=MIN_TREEIFY_CAPACITY
(默认64),就会进行树化(红黑树),否则仍然采用数组扩容机制
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
hashSet.add("java");
hashSet.add("php");
hashSet.add("java");
System.out.println(hashSet);
}
}
class HashSet{
// PRESENT就是HaseSet为了用HashMap所以加了一个占位符
// PRESENT是静态的,所以被HashSet类的所有对象共享
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
//跳进HashMap中的put方法
// map正常添加完元素返回的应该是null
return map.put(e, PRESENT)==null;
}
}
class HashMap{
//第一次使用时初始化,长度为2的次幂,也可以为0
transient Node<K,V>[] table;
// 默认初始化容量为16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
// 默认初始化负载因子0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//当链表的长度大于等于8时,就去判断是把链表变成红黑树,还是对table数组进行扩容
static final int TREEIFY_THRESHOLD = 8;
//在treeifyBin方法中,如果table数组的长度小于64就不会将链表转换为红黑树,而是对table数组进行扩容
static final int MIN_TREEIFY_CAPACITY = 64;
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
// 计算key应该存放的位置
// (h = key.hashCode()) ^ (h >>> 16)是为了尽量让不同的key得到不同的hash值,从而避免碰撞
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >&