Java 数据结构 -- 12.Java 8 数据结构 HashSet

本文深入探讨了 Java 8 中的 HashSet 数据结构,揭示了其实现原理是基于 HashMap,HashSet 作为 HashMap 的装饰器,通过 HashMap 的操作来实现自身的功能。同时,文章也介绍了 LinkedHashSet,它是通过调用特定的构造方法实现有序存储,其内部依赖于 LinkedHashMap。对于 Set 接口的这两种实现,分析了它们各自的特点和用途。
摘要由CSDN通过智能技术生成

前言

书接上文,上一篇中对于 Set 接口与 AbstractSet 抽象实现类做了介绍与分析,本篇将对 Set 最终实现类 HashSet 与 LinkedHashSet 做介绍与分析。

先来看下 HashSet 的源码

/**
 * 这个类实现了 Set 接口,有一个 hash table(事实上是一个 HashMap)支持。它对于套的迭代顺序不做保证,此处
 * 特指,它不保证顺序能一直保持一致。这个类允许 null 元素,结社 hash 功能正确地在桶中分散了元素。
 *
 * 这个类为基本操作(add,remove,contains 和 size)提供了与事件一直的表现,迭代这个套锁需要的时间与 
 * HashSet 实例的长度(元素数量)加上支持的 HashMap 实例的“容量”(桶个数)成正比。因此,如果迭代性能很重要
 * 的话,不将初始容量设置的太高(或者加载因子太低)就是很重要的。
 *
 * 注意这个实现类不是线程安全的。如果多线程并发地访问一个 hash set,并且至少有一个线程更改了 set,它必须从
 * 外部实现线程安全。这通常通过对封装了 set 的对象实现线程安全来完成。
 *
 * 如果没有类似的对象存在,set 应该使用 Collections#synchronizedSet 方法“包装”。这最好在创建的时候完
 * 成,来防止意外的对于 set 的非线程安全的访问: <pre>
 *   Set s = Collections.synchronizedSet(new HashSet(...));</pre>
 *
 * 这个类的 iterator 方法返回的迭代器是 fail-fast 的:如果 set 在被创建后的任何时间点被更改了,以除了通过
 * 迭代器自己的 remove 方法的其他任何方式,迭代器会抛出一个 ConcurrentModificationException。因此,在
 * 并发修改操作时,迭代器失败地快速和干净,而不是在未来某个不确定的时间点,冒险做武断的,描述不清的动作。
 * 
 * 注意一个迭代器的 fail-fast 行为是不能被保证的,通常来说,不可能对出现的非线程安全的同时修改操作做任何硬性
 *的保证。基于最佳性能的基础考虑,Fail-fast 迭代器抛出一个 ConcurrentModificationException。因此,建立
 * 在这中异常上写出的程序的正确性将会是不健壮的:迭代器的 fail-fast 行为应当植被用于检查 bugs。
 * 
 * HashSet 继承自 AbstractSet 抽象类,实现了 Set 接口,Cloneable 接口以及 Serializable 接口。
 */

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
   
    static final long serialVersionUID = -5024744406713321676L;

		/**不参与序列化的部分**/
    private transient HashMap<E,Object> map;

    /**与一个在支持 map 中的对象相关的壳值**/
    private static final Object PRESENT = new Object();

    /**
     * 构造一个新的,空的 set,支持的 HashMap 实例有模式容量(16)和加载因子(0.75)
     */
    public HashSet() {
   
        map = new HashMap<>(); //构造一个空 HashMap
    }

    /**
     * 构造一个新的包含指定数据结构中的元素的 set,HashMap 被使用默认加载因子(0.75)和一个足够包含指定数
     * 据结构中元素的初始化容量来构造。
     */
    public HashSet(Collection<? extends E> c) {
   
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); //传参构造一个空 HashMap
        addAll(c); //调用 addAll 方法
    }

    /**
     * 构造一个新的,空的 set,支持 HashMap 实例有指定的初始容量和指定的加载因子
     */
    public HashSet(int initialCapacity, float loadFactor) {
   
        map = new HashMap<>(initialCapacity, loadFactor); //传参构造一个空的 HashMap
    }

    /**
     * 构造一个新的,空的 set,支持 HashMap 实例有指定的初始容量和模式的加载因子(0.75)。
     */
    public HashSet(int initialCapacity) {
   
        map = new HashMap<>(initialCapacity)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值