HashSet底层机制总结,HashMap底层转成红黑树的机制
HashSet底层机制:
1.HashSet底层是 HashMap ,底层维护了一个数组 + 单向链表
2.添加一个元素时,先得到hash值 -会转成->索引值
3.找到存储数据表 table,看这个索引位置是否已经存放的有元素
4.如果没有,直接加入
5.如果有,调用 equals比较,如果相同,就放弃添加,, 如果不相同,则添加到最后
6.在Java8中如果一条链表的元素个数到达 TREEIFY_THRESHOLD(默认是8),
并且 table的大小>=MIN_TREEIFY_CAPACITY(默认64)就会进行树化(红黑树)
HashSet的扩容和转成红黑树机制
1.HashSe底层是 HashMap,第一次添加时, table数组扩容到16,
临界值(threshold)是 16 * 加载因子 ( load Factor)是0.75 = 12
2.如果 table数组使用个数size到了临界值12, 就会扩容到16 * 2=32,新的临界值就是32 * 0.75=24,依次类推
代码
1 public class HashSetSource { 2 public static void main(String[] args) { 3 HashSet hashSet = new HashSet(); 4 hashSet.add("java"); 5 hashSet.add("php"); 6 hashSet.add("java"); 7 System.out.println("set" + hashSet); 8 } 9 } 10 11 //执行步骤 12 13 14 //1.执行hashSet 15 public HashSet() { 16 map = new HashMap<>(); 17 } 18 //2.执行 add() 19 public boolean add(E e) { 20 return map.put(e, PRESENT)==null; //static final Object PRESENT = new Object(); PRESENT起到占位的目的 21 } 22 //3.执行put(),该方法会执行hash(hash(key))得到key对应的hash值,此值并不完全等价于hashcode 23 public V put(K key, V value) { //key = "java" , value = PRESENT 共享,因为是静态的 24 return putVal(hash(key), key, value, false, true); 25 } 26 27 /* 28 //----> Force Step Into 29 static final int hash(Object key) { 30 int h; 31 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 32 //按位异或再右移16位 33 //为了避免碰撞 34 } 35 36 */ 37 //4.执行 putVal 38 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, 39 boolean evict) { 40 Node<K,V>[] tab; Node<K,V> p; int n, i;//定义了辅助变量 41 //table 是 HashMap 的一个数组,类型是 Node[] 42 //if语句 表示如果当前table是null,或者大小为0 43 //就第一次扩容到16个空间 44 if ((tab = table) == null || (n = tab.length) == 0) 45 n = (tab = resize()).length; 46 //(1)根据key得到hash,去计算该key应存放到table表的哪个索引位置, 47 // 并且把这个位置的对象,赋给辅助变量p 48 //(2)判断p是否为null 49 // (2.1)如果p为null,表示还没有存放过元素, 50 // 就创建一个Node(hash = ,key="java", value=PRESENT,null) 51 if ((p = tab[i = (n - 1) & hash]) == null) 52 tab[i] = newNode(hash, key, value, null); 53 else { 54 Node<K,V> e; K k; //辅助变量 55 //如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样 56 //并且 满足准备加入的key和p指向的Node节点的key是同一个对象 或者 内容相同 57 //就不能加入 58 if (p.hash == hash && 59 ((k = p.key) == key || (key != null && key.equals(k)))) 60 e = p; 61 //再判断p是不是一颗红黑树 62 //如果是调用putTreeVal 63 else if (p instanceof TreeNode) 64 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); 65 else {//如果 tabLe对应索引位置,已经是一个链表,就使用for循环比较 66 //(1)依次和该链表的每一个元素比较后,都不相同,则加入到该链表的最后 67 // 注意:注意在把元素添加到链表后,立即判断该链表是否已经达到8个结点就 68 // 调用treeifyBin()对当前这个链表进行树化(转成红黑树) 69 // 注意:转成红黑树要进行条件判断,判断条件如下 70 // if(tab==NULL || (n= tab. Length) < MIN_TREEIFY_CAPACITY(64)) // resize(); 71 // 如果上面条件成立,先扩容table 72 // 只有上面条件不成立时,才进行转成红黑树 73 //(2)依次和该链表的每一个元素比较过程中,如果有相同情况,就直接 break 74 for (int binCount = 0; ; ++binCount) { 75 if ((e = p.next) == null) { 76 p.next = newNode(hash, key, value, null); 77 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 78 treeifyBin(tab, hash); 79 break; 80 } 81 if (e.hash == hash && 82 ((k = e.key) == key || (key != null && key.equals(k)))) 83 break; 84 p = e; 85 } 86 } 87 if (e != null) { // existing mapping for key 88 V oldValue = e.value; 89 if (!onlyIfAbsent || oldValue == null) 90 e.value = value; 91 afterNodeAccess(e); 92 return oldValue; 93 } 94 } 95 ++modCount; 96 //size每加入一个Node节点, size++,不管是直接在table上加的,还是在table上的链表上加的 97 if (++size > threshold) 98 resize(); 99 //在HashMap里是空方法,留给子类去实现,比如去形成一个有序的链表 100 afterNodeInsertion(evict); 101 return null; 102 } 103 104 105 final Node<K,V>[] resize() { 106 Node<K,V>[] oldTab = table; 107 int oldCap = (oldTab == null) ? 0 : oldTab.length; 108 int oldThr = threshold; 109 int newCap, newThr = 0; 110 if (oldCap > 0) { 111 if (oldCap >= MAXIMUM_CAPACITY) { 112 threshold = Integer.MAX_VALUE; 113 return oldTab; 114 } 115 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && 116 oldCap >= DEFAULT_INITIAL_CAPACITY) 117 newThr = oldThr << 1; // double threshold 118 } 119 else if (oldThr > 0) // initial capacity was placed in threshold 120 newCap = oldThr; 121 else { // zero initial threshold signifies using defaults 122 newCap = DEFAULT_INITIAL_CAPACITY; 123 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); 124 } 125 if (newThr == 0) { 126 float ft = (float)newCap * loadFactor; 127 newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? 128 (int)ft : Integer.MAX_VALUE); 129 } 130 threshold = newThr; 131 @SuppressWarnings({"rawtypes","unchecked"}) 132 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; 133 table = newTab; 134 if (oldTab != null) { 135 for (int j = 0; j < oldCap; ++j) { 136 Node<K,V> e; 137 if ((e = oldTab[j]) != null) { 138 oldTab[j] = null; 139 if (e.next == null) 140 newTab[e.hash & (newCap - 1)] = e; 141 else if (e instanceof TreeNode) 142 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); 143 else { // preserve order 144 Node<K,V> loHead = null, loTail = null; 145 Node<K,V> hiHead = null, hiTail = null; 146 Node<K,V> next; 147 do { 148 next = e.next; 149 if ((e.hash & oldCap) == 0) { 150 if (loTail == null) 151 loHead = e; 152 else 153 loTail.next = e; 154 loTail = e; 155 } 156 else { 157 if (hiTail == null) 158 hiHead = e; 159 else 160 hiTail.next = e; 161 hiTail = e; 162 } 163 } while ((e = next) != null); 164 if (loTail != null) { 165 loTail.next = null; 166 newTab[j] = loHead; 167 } 168 if (hiTail != null) { 169 hiTail.next = null; 170 newTab[j + oldCap] = hiHead; 171 } 172 } 173 } 174 } 175 } 176 return newTab; 177 } 178

浙公网安备 33010602011771号