HashSet源码(add操作,put方法)

167 阅读2分钟

以下都是本人在自学中对知识的理解,可能有许多不足之处,还望多多包含,若能帮助到你,倍感荣幸

HashSet的底层是HashMap

//HashSet无参构造
public HashSet() {
    map = new HashMap<>();
}
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // 默认负载因子0.75
}

4个构造器

4个构造器.png

add方法

// HashSet add()方法
public boolean add(E e) {
    // HashMap 是传入 key-value ,而 HashSet把 仅传入key ,values默认是一个常量
    return map.put(e, PRESENT)==null;
}

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

// hash()方法,通过hashCode值 经过运算 得到 hash , 注意:hashCode值 不等于 hash
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;  // 局部变量(辅助作用)
    
    // 判断table表数组是不是为null ,或 长度为 0 ,是的话 则进行扩容 ,默认情况下 扩容为 16
    if ((tab = table) == null || (n = tab.length) == 0)  
        n = (tab = resize()).length;
    
 // 通过 hash值 再次经过运算 得到 对应的 table表的索引 ,判断该索引处是否为 null ,若为null 
 // 则在索引位置直接添加该元素
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
  
    else {
        Node<K,V> e; K k;
        // 如果该索引有元素的话 ,则先判断 该元素 与 key 是否相同
        // key相同的判断标准: == 相同 或 调用 所添加元素的equals()方法判断 ,二者有一则相同
        if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;    
        
        // 如果第一个元素不相同,则在判断 该索引所在的结构是不是一棵红黑树  ,
        // 是树的话,则在树里进行添加操作
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        
        //如果 第一个元素不同 ,所在结构又不是一棵树 ,那就for循环遍历该链表所有元素
        //判断是否有相同元素 ,有相同就放弃添加,替换value ,没有就添加到链表末尾
        else {
            for (int binCount = 0; ; ++binCount) {  // 死循环
                if ((e = p.next) == null) {   // 判断下一个元素是不是null ,是null则添加
                    p.next = newNode(hash, key, value, null);
                    // 添加完成后 判断是否进行树化
                    if (binCount >= TREEIFY_THRESHOLD - 1) 
                        treeifyBin(tab, hash);
                    break;
                }   
                // 如果下一个元素不是null ,则比较 hash 和 key 是否相同 
                // 相同则跳出for , 不同则继续for 比较下一个元素
                if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        // 如果元素相同(重复),则 新key的 value 取代 旧key的value
        if (e != null) { 
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
               e.value = value;
               afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    // 已添加元素个数超过阈值则扩容   threshold = table表数组长度 * 负载因子
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

以上都是本人在自学中对知识的理解,可能有许多不足之处,请多多包含