类前注释

      此类实现了Set接口,支持哈希表(实际上是一个HashMap)实例。它不保证迭代的顺序;特别是,它不保证顺序的亘久不变。HashSet之处null元素。
      假设哈希函数将元素正确地分散在bucket中,该类为基本操作(add,remove,contains和size)提供恒定的时间性能。遍历该集合需要时间正比于HashSet实例的大小(元素的数量)加上其底层HashMap实例的"容量"(桶的数量)的总和。 因此,不要将初始容量设置得太高(或负载因数过低),因为迭代性能很重要,非常重要。
      请注意,此实现不是同步的。如果多个线程同时访问HashSet,并且至少有一个线程修改了HashSet,则必须在外部进行同步,这通常是通过对某个对象进行同步来实现的那自然地封装集合。如果该对象不存在,该组应该被"包装"使用Collections.synchronizedSet方法。 这最好在创建时完成,以防止对set的意外非同步访问:

Set s = Collections.synchronizedSet(new HashSet(...));

      此类的iterator方法返回的迭代器是快速失败的:如果集合随时修改创建迭代器之后,以任何方式除非通过迭代器自身的remove方法,迭代器将抛出ConcurrentModificationException。 因此,在并发的修改时,迭代器很快就会失败,而不是在将来不确定的时间g发生不确定性的行为。
      请注意,不能保证迭代器的快速失败行为。通常来说,在存在不同步的并发修改的情况下,不可能做出任何严格的保证。 快速迭代器会尽最大努力抛出ConcurrentModificationException,因此,编写依赖于此异常的程序的正确性是错误的:迭代器的快速故障行为仅应用于检测错误。

类图

请输入图片描述

成员变量

//HashSet底层是一个HashMap,key是泛型,value是Object
private transient HashMap<E,Object> map;

//虚拟的值,用于上面的map中的value
private static final Object PRESENT = new Object();

HashSet底层是使用HashMap实现的,只是只使用了它的Key,Value是一个统一的Object对象

构造方法

//构造一个新的空集; 支持的<tt> HashMap </ tt>实例具有默认的初始容量(16)和负载系数(0.75)。
public HashSet() {
    map = new HashMap<>();
}

/**
 *构造一个新集合,其中包含指定集合中的元素。HashMap是使用默认加载因子(0.75)和足以容纳指定集合中
 *的元素的初始容量创建的。
*/
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);
}

/**
 * 构造一个新的空的哈希集。(此构造函数仅供LinkedHashSet使用。)
 * 支持的HashMap实例是具有指定的初始容量和指定的负载因子的LinkedHashMap。
 */
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

euqals

HashSet<Integer> set1 = new HashSet<>();
set1.add(1);
set1.add(2);
set1.add(3);
set1.add(4);

TreeSet<Integer> set2 = new TreeSet<>();
set2.add(1);
set2.add(2);
set2.add(3);
set2.add(4);

System.out.println(set1.equals(set2));//true

      答案出乎我们的意料,set1和set2的类型都不一样,咋还相等了呢!这就需要查看AbstractSetequals方法了。

/**
 * 指定的对象与此Set的相等性。 
 * 如果给定对象也是Set,这两组具有相同的大小,以及给定的所有成员都包含在这个集合返回true。
 * 这样可以确保equals方法可在Set接口的不同实现中正常运行。
 *
 * 此实现首先检查指定的对象是Set,则返回true。 
 * 然后,它检查指定的Set的size是相同的; 如果不是,则返回false。
 * 如果是这样,则返回containsAll(Collection o)。
 */
public boolean equals(Object o) {
    if (o == this)
        return true;

    //不是Set类型,返回false
    if (!(o instanceof Set))
        return false;
    Collection<?> c = (Collection<?>) o;
    //集合大小不同,返回false
    if (c.size() != size())
        return false;
    try {   //判断另一个集合中的元素是否都在
        return containsAll(c);
    } catch (ClassCastException unused)   {
        return false;
    } catch (NullPointerException unused) {
        return false;
    }
}

学习HashSet前如果学习了HashMap的话将十分简单,去吧~

Last modification:September 16th, 2020 at 01:18 pm
如果觉得我的文章对你有用,请随意赞赏