HashSet如何保证元素的唯一性

来源:互联网 发布:杭州阿里妈妈软件 编辑:程序博客网 时间:2024/03/29 05:48


底层数据结构是哈希表(元素是链表的数组),也就是说,保证元素的唯一性的第一层保证就是元素的HashCode。下面我们从源码的角度来分析:当我们向HashSet中插入一个元素的时候,发生了什么。

 public HashSet() {        map = new HashMap<>();    }
这里HashSet的构造函数调用了HashMap,
public class HashMap<K,V>    extends AbstractMap<K,V>    implements Map<K,V>, Cloneable, Serializable
HashMap是一个继承了AbstractMap的类,那么我们来看看它实现了什么
    public V put(K key, V value) {        if (key == null)            return putForNullKey(value);        int hash = hash(key.hashCode());        int i = indexFor(hash, table.length);        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            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;    }
这是HashMap中的put方法,这里的value暂时不管,查看源码可以发现它似乎是随机取的一个对象地址而已,具体有什么作用我也不清楚。

key是我们要插入HashMap的元素。假设这个元素为null时,则return putForNullKey(value)

    private V putForNullKey(V value) {        for (Entry<K,V> e = table[0]; e != null; e = e.next) {            if (e.key == null) {                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;            }        }        modCount++;        addEntry(0, null, value, 0);        return null;    }

这段代码表示,假如我们传入了一个null,那么putForNullKey会根据我们传入null时附带的value值去计算,HashSet表的第一个链表是否为null,如果是null,则将我们这个(0, null, value, 0)插入其中,如果第一个链表不为null,就判断其中的元素的key值是不是与null,如果是null,就说明,之前已经传过一个null的元素到hashset中了,则不再向第一个链表中增添元素,并且返回旧的null值所对应的value值。那这里跟我们要理解的唯一性关系不大。

接下来回来put函数,put函数先根据我们传入的key值,对其进行了hash运算,然后再根据hash值算出了索引i。索引i所对应的table中的链表。然后for循环中依次对链表中的元素的hash值进行检查(因为不用调用到equals方法,所以比较高效,先进行),假如hash值相同,则再对元素的key值的引用地址或者用equals方法对key的真实内容进行比较。如果比较结果是key值已经存在于表中,那么就不对其进行插入,而是返回原本的key值对应的value值。

如果这个表中的元素不存在key值相同的元素,那么就将(hash, key, value, i)插入。

由以上源码的分析可以看出,唯一性的两个保证是hash值还有equals方法,但是默认的equals方法只比较地址,所以要想真正实现唯一性,需要重写equals方法。






阅读全文
0 0
原创粉丝点击