HashSet底层机制总结,HashMap底层转成红黑树的机制

HashSet底层机制:

HashSet的添加元素底层是如何实现的(hash() + equals() )

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,依次类推

3.在Java8中如果一条链表的元素个数到达 TREEIFY THRESHOLD (默认是8) 并且 table的大小>=MIN_TREEIFY_CAPAITY (默认64),就会进行树化红黑树,否则仍然采用数组扩容机制

代码

  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  

 

posted @ 2021-11-16 10:28  肖万  阅读(831)  评论(0)    收藏  举报