Java集合框架:了解HashSet

HashSet

基于HashMap实现的散列集

目录

HashSet继承关系

HashSet源码分析 

HashSet总结


HashSet继承关系

HashSet实现了Serializable接口,支持序列化,可通过序列化传输

HashSet实现了Cloneable接口,覆盖了clone()方法,能被克隆

HashSet继承了AbstractSet抽象类和实现了Set接口,可以进行集的相关操作

HashSet源码分析 

HashSet构造函数:

    /**
     * 构造一个空集
     * 初始容量initailCapacity = 16
     * 负载因子loadFacto = 0.75
     */
    public HashSet() {
        map = new HashMap<>();  // 底层实现使用HashMap存储数据
    }

    /**
     * 构造一个包含指定集合中元素的新集
     * 初始容量initailCapacity = 容纳指定集合中的元素
     * 负载因子loadFactor = 0.75
     * 
     * @param c the collection whose elements are to be placed into this set
     * @throws NullPointerException if the specified collection is null
     */
    public HashSet(Collection<? extends E> c) {
        // 初始容量 = Max(指定集合元素数量/0.75 + 1,16), 使loadFactor <= 0.75
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); 
        addAll(c);
    }

    /**
     * 构造一个 指定初始容量 和 指定负载因子 的新集
     *
     * @param      initialCapacity   the initial capacity of the hash map
     * @param      loadFactor        the load factor of the hash map
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero, or if the load factor is nonpositive
     */
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }

    /**
     * 构造一个 指定初始容量 和 默认负载因子=0.75 的新集
     *
     * @param      initialCapacity   the initial capacity of the hash table
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero
     */
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

    /**
     * 构造一个 指定初始容量 和 指定加载因子 新集, 以LinkedHashMap为实现
     * 此构造函数仅由LinkedHashSet使用
     * 
     * @param      initialCapacity   the initial capacity of the hash map
     * @param      loadFactor        the load factor of the hash map
     * @param      dummy             ignored (distinguishes this
     *             constructor from other int, float constructor.)
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero, or if the load factor is nonpositive
     */
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

HashSet增删操作:

    /**
     * 若此元素集中不包含任何元素e2, 使Objects.equals(e, e2), 则将指定的元素e添加到该元素集中
     * 若此集已包含该元素, 则调用将保留该集不变, 返回false
     *
     * @param e element to be added to this set
     * @return {@code true} if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    /**
     * 若此元素集中包含任何元素o, 使Objects.equals(o, o2), 则删除元素o后返回true, 否则返回false
     *
     * @param o object to be removed from this set, if present
     * @return {@code true} if the set contained the specified element
     */
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

    /**
     * 从集中删除所有元素
     */
    public void clear() {
        map.clear();
    }

HashSet其他操作:

    /**
     * 返回迭HashMap的key迭代器
     */
    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

    /**
     * 返回此集中的元素数量
     *
     * @return the number of elements in this set (its cardinality)
     */
    public int size() {
        return map.size();
    }

    /**
     * 若此集不包含任何元素, 则返回true
     *
     * @return {@code true} if this set contains no elements
     */
    public boolean isEmpty() {
        return map.isEmpty();
    }

    /**
     * 当且仅当此集包含元素e使Objects.equals(o, e)时, 返回true
     *
     * @param o element whose presence in this set is to be tested
     * @return {@code true} if this set contains the specified element
     */
    public boolean contains(Object o) {
        return map.containsKey(o);
    }

HashSet序列化操作:

    /**
     * 将集保存到流中(发送实例容量和负载因子, 然后发出集的大小, 然后发出其所有元素)
     *
     * @serialData The capacity of the backing {@code HashMap} instance
     *             (int), and its load factor (float) are emitted, followed by
     *             the size of the set (the number of elements it contains)
     *             (int), followed by all of its elements (each an Object) in
     *             no particular order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        // Write out any hidden serialization magic
        s.defaultWriteObject();

        // Write out HashMap capacity and load factor
        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());

        // Write out size
        s.writeInt(map.size());

        // Write out all elements in the proper order.
        for (E e : map.keySet())
            s.writeObject(e);
    }

    /**
     * 从流中重构HashSet
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {

        s.defaultReadObject(); // 从此流中读取当前类的非静态和非瞬态字段, 只能从readObject方法中调用, 否则抛出NotActiveException

        // 读取容量并验证
        int capacity = s.readInt();
        if (capacity < 0) {
            throw new InvalidObjectException("Illegal capacity: " +
                                             capacity);
        }

        // 读取负载因子并验证
        float loadFactor = s.readFloat();
        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new InvalidObjectException("Illegal load factor: " +
                                             loadFactor);
        }

        // 读取大小并验证
        int size = s.readInt();
        if (size < 0) {
            throw new InvalidObjectException("Illegal size: " +
                                             size);
        }

        // 根据大小和负载因子设置容量, 确保HashMap至少已满25%, 但要限制小于最大容量
        capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
                HashMap.MAXIMUM_CAPACITY);

        // Constructing the backing map will lazily create an array when the first element is
        // added, so check it before construction. Call HashMap.tableSizeFor to compute the
        // actual allocation size. Check Map.Entry[].class since it's the nearest public type to
        // what is actually created.
        SharedSecrets.getJavaObjectInputStreamAccess()
                     .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity));

        // Create backing HashMap
        map = (((HashSet<?>)this) instanceof LinkedHashSet ?
               new LinkedHashMap<>(capacity, loadFactor) :
               new HashMap<>(capacity, loadFactor));

        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            @SuppressWarnings("unchecked")
                E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }

HashSet总结

HashSet底层通过维护一个HashMap实现

HashSet初始的默认容量=16,默认负载因子=0.75

HashSet数据结构保证了数据的唯一性,但不保证数据的有序性(唯一,无序)

HashSet是线程不安全的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值