HashSet HashMap 源码阅读笔记

hashcode() 与 equals() 应一起重写,在HashMap 会先调用hash(key.hashcode()) 找到对应的entry数组位置 (一般初始是16,2^x,rehash后会翻倍),再在这个entry链表上equals判断是否存在相同元素。

所以当重写equals时没保证hashcode出的值的一致性,会导致hash到不同的数组位置 插入重复的元素。

※String类的hashcode是通过各个位置的char的ascii码计算Σx*31^(len-i)得到的※

HashSet通过HashMap实现,其中每次插入的value值都是一个Object的常量。iterator()返回map的hashmap的keyiterator。

HashMap成员变量

 1 //默认初始化map的容量:16
 2 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
 3 //map的最大容量:2^30
 4 static final int MAXIMUM_CAPACITY = 1 << 30;
 5 //默认的填充因子:0.75,能较好的平衡时间与空间的消耗
 6 static final float DEFAULT_LOAD_FACTOR = 0.75f;
 7 //将链表(桶)转化成红黑树的临界值
 8 static final int TREEIFY_THRESHOLD = 8;
 9 //将红黑树转成链表(桶)的临界值
10 static final int UNTREEIFY_THRESHOLD = 6;
11 //转变成树的table的最小容量,小于该值则不会进行树化
12 static final int MIN_TREEIFY_CAPACITY = 64;
13 //上图所示的数组,长度总是2的幂次
14 transient Node<K,V>[] table;
15 //map中的键值对集合
16 transient Set<Map.Entry<K,V>> entrySet;
17 //map中键值对的数量
18 transient int size;
19 //用于统计map修改次数的计数器,用于fail-fast抛出ConcurrentModificationException
20 transient int modCount;
21 //大于该阈值,则重新进行扩容,threshold = capacity(table.length) * load factor
22 int threshold;
23 //填充因子
24 final float loadFactor;

长度为2^n是取模运算快,只需要&(size-1)即可

jdk1.8中 桶中 如果链表长度超过8 会重拍成红黑树,依照hashcode值排序

总数量超过threshold = capacity * loadfactor 会进行resize重拍。需要遍历整个table[],性能较低,如果提前知道map大小,最好在初始化的时候提前设置。

在使用iterator迭代器遍历(for each)的时候如果在遍历途中删除map中元素,会抛出ConcurrentModificationException(!!删除倒数第二个不会报错),最好使用iterator内部的删除方法iterator.remove()

 hashmap允许key和value为null,线程不安全

原文地址:https://www.cnblogs.com/chafanbusi/p/10620958.html