HashSet集合的add()方法的源码

interface Collection {
    ...
}
interface Set extends Collection {
    ...
}
class HashSet implements Set {
    private static final Object PRESENT = new Object();
    private transient HashMap<E,Object> map;
    
    public HashSet() {
        map = new HashMap<>();
    }
    
    public boolean add(E e) { //e=hello,world
        return map.put(e, PRESENT)==null;
    }
}
class HashMap implements Map {
    public V put(K key, V value) { //key=e=hello,world
    
        //看哈希表是否为空,如果空,就开辟空间
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        
        //判断对象是否为null
        if (key == null)
            return putForNullKey(value);
        
        int hash = hash(key); //和对象的hashCode()方法相关
        
        //在哈希表中查找hash值
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            //这次的e其实是第一次的world
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
                //走这里其实是没有添加元素
            }
        }

        modCount++;
        addEntry(hash, key, value, i); //把元素添加
        return null;
    }
    
    transient int hashSeed = 0;
    
    final int hash(Object k) { //k=key=e=hello,
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode(); //这里调用的是对象的hashCode()方法

        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
}
//对应源码 addEntry(hash, key, value, i); //把元素添加
void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
    }
    hs.add("hello");//由于table里面没有,直接进addEntry
    hs.add(
    "world");//同上
    hs.add(
    "java");//同上
    hs.add(
    "world");//table里已经存在,(hash和equals相等),则在put()时,用新值替代老值。ps:这里的老值和新值都是world。

总结:

首先比较哈希值
    如果相同,继续走,比较地址值或者走equals()
    如果不同,就直接添加到集合中
按照方法的步骤来说:
    先看hashCode()值是否相同
        相同:继续走equals()方法
            返回true:说明元素重复,就不添加
            返回false:说明元素不重复,就添加到集合
        不同:就直接把元素添加到集合
如果类没有重写这两个方法,默认使用的Object()。一般磊说不会相同。
而String类重写了hashCode()和equals()方法,所以,它就把内容相同的字符串去掉,只留下一个。

原文地址:https://www.cnblogs.com/qq-757617012/p/4285627.html