HashSet源码分析

栏目: 编程工具 · 发布时间: 7年前

内容简介:HashSet是一个HashMap的一个实例,它不保证它的元素们的相对顺序始终是一样的。它也允许null元素的存在。和其他的集合一样,它也是线程不安全,具有fail-fast机制的。上面是它的2个属性。上面是4种构造本类实例的方法。

HashSet是一个HashMap的一个实例,它不保证它的元素们的相对顺序始终是一样的。它也允许null元素的存在。和其他的集合一样,它也是线程不安全,具有fail-fast机制的。

private transient HashMap<E,Object> map;

// 这里构造了一个虚拟的对象来充当HashMap中的value值。
//这个对象是用final修饰的,所以这个value值也是保持不变的
private static final Object PRESENT = new Object();
复制代码

上面是它的2个属性。

public HashSet() {
    map = new HashMap<>();
}

public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}

public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
    map = new HashMap<>(initialCapacity);
}

复制代码

上面是4种构造本类实例的方法。

public Iterator<E> iterator() {
    return map.keySet().iterator();
}
复制代码

HashSet的迭代器也是来自HashMap。从这里可以看出HashSet中的元素其实是HashMap中的key的集合,因为该迭代器就是遍历的HashMap的key集合。

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}复制代码

上面是他的add方法。从这里也可以看出value就是用这个虚拟的对象来充当的。

其他的方法也都是基于HashMap来实现的。

另外,HashSet是怎么保证元素不重复的呢?因为它的add方法其实就是HashMap的put方法实现的,所以它的这个性质也是由这个方法来保证的。

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;

        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);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}复制代码

上面就是底层方法的实现,说明下期中一些变量的作用。p节点是用来接收集合中的第一个元素以及利用它来调用next来遍历集合中的其他元素,而e节点则是来接收p节点。用K k来接收集合中元素的key值。

if (p.hash == hash &&
    ((k = p.key) == key || (key != null && key.equals(k))))
    e = p;复制代码

从上面这段代码可以看出先是比较集合中的元素的hash值是否与要添加的元素的hash值相等,以及他们的key是否相等(此处是用==来判断的);然后用元素的equals方法比较key值是否相等。如果条件成立则把p节点赋给e节点,此时说明要加入的元素的hash值与集合中的一个元素的hash值相等了,也就是说对于key有了相同的映射。今儿判断e是否为null,若不为null,就把集合中的这个元素的value值赋给oldValue作为返回值,然后把要添加的元素的value值赋给e节点。

从上面的分析可以看出它是怎么保证元素的不重复的性质,也知道了其实HashMap本身的元素们也是具有不重复的性质的。

Set<String> set = new HashSet();
set.add(null);
set.add("null");
System.out.println(set);//[null, null]复制代码

最后发现了一个有趣的地方。


以上所述就是小编给大家介绍的《HashSet源码分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

智能

智能

[法]弗雷德里克·马特尔 / 君瑞图、左玉冰 / 商务印书馆 / 2015-8 / 59.90

揭示数字化主流大趋势的最新权威论著 《主流》作者的最新力作!与法国秋季新版同步上市! 面对数字化时代的到来,美国、欧盟、中国、俄罗斯、印度、巴西、古巴、伊朗、南非、韩国、新加坡、肯尼亚、墨西哥、日本等世界各国各地区正在如何应对? 在国际地缘政治格局下如何把握数字化主流的大趋势? 谷歌、苹果、脸书、亚马逊、阿里巴巴、腾讯、中兴、华为等大家熟知的网络巨头接受了作者的采访。作者的......一起来看看 《智能》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具