Java数据结构详解(六)-HashSet

来源:互联网 发布:看日本综艺节目的软件 编辑:程序博客网 时间:2024/06/06 05:43

HashSet

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

此类为基本操作提供了稳定性能,这些基本操作包括 add、remove、contains 和 size,假定哈希函数将这些元素正确地分布在桶中。对此 set 进行迭代所需的时间与 HashSet 实例的大小(元素的数量)和底层 HashMap 实例(桶的数量)的“容量”的和成比例。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。

注意,此实现不是同步的。如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步。这通常是通过对自然封装该 set 的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装” set。最好在创建时完成这一操作,以防止对该 set 进行意外的不同步访问:

Set s = Collections.synchronizedSet(new HashSet(…));此类的 iterator 方法返回的迭代器是快速失败 的:在创建迭代器之后,如果对 set 进行修改,除非通过迭代器自身的 remove 方法,否则在任何时间以任何方式对其进行修改,Iterator 都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来在某个不确定时间发生任意不确定行为的风险。

注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器在尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误做法:迭代器的快速失败行为应该仅用于检测 bug。

HashSet的字段

    //底层使用的是HashMap实例.    private transient HashMap<E,Object> map;    // Dummy value to associate with an Object in the backing Map    //用于HashMap中的Value值,    private static final Object PRESENT = new Object();

HashSet的构造方法

无参构造器

    public HashSet() {        //底层实际用的是 HashMap实例        map = new HashMap<>();    }

有参构造器

    public HashSet(Collection<? extends E> c) {        //构造一个包含指定 collection 中的元素的新 set。        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));        addAll(c);    }

    public HashSet(int initialCapacity) {        //指定初始化容量        map = new HashMap<>(initialCapacity);    }

    public HashSet(int initialCapacity, float loadFactor) {        //指定初始化容量 和加载因子        map = new HashMap<>(initialCapacity, loadFactor);    }

HashSet的add,remove

add

    public boolean add(E e) {        将参数 e 作为HashMap的key,将静态变量present作为value.put到HashMap里面.        return map.put(e, PRESENT)==null;    }

remove

    public boolean remove(Object o) {        return map.remove(o)==PRESENT;    }

HashSet 底层用的是HashMap 利用了HashMap的Key不可以重复,value可以重复的特点.

原创粉丝点击