无序之美:Java HashSet解析与应用

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 无序之美:Java HashSet解析与应用

HashSet 底层基于 HashMap 来实现,是一个不允许有重复元素并且无序的集合。HashSet 允许有 null 值,但是只能有一个。HashSet 不是线程安全的,如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。HashSet 继承自 AbstractSet,并且实现了 Set、Cloneable、Serializable 接口。

HashSet 还有一个子类,LinkedHashSet,LinkedHashSet 集合也是根据元素的 hashCode 值来决定元素的存储位置,但是它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序来保存的。也就是说,当遍历 LinkedHashSet 集合里的元素时,会按照元素插入顺序来访问元素。

总的来说,HashSet 只是在 HashMap 的基础上包装了一层,基本都使用的 HashMap 的方法。

成员变量

容器 map

private transient HashMap<E,Object> map;

使用 HashMap 的 key 保存 HashSet 中所有元素。

静态 map 值

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

定义一个静态的 Object 对象作为上面定义的 HashMap 的 value。

由于 HashSet 底层使用的是 map 中的键来存储数据,那么在新增数据的时候,原来 map 的值全部使用这个静态的对象。即调用map.put(数据, PRESENT)

构造方法

无参构造:默认创建 HashMap

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

无参数的构造函数,此构造函数创建一个大小为 16,加载因子为 0.75 的 HashMap 用于存储数据(联系到前面学习的HashMap)。

指定初始化集合

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

为了避免扩容操作,首先需要对初始化集合的大小与默认大小 16 进行比较,取最大然后初始化 map。之后调用 addAll 方法将初始化集合中的元素添加到 HashSet 中的 map 的 key 中。

指定容量和负载因子

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

指定容量

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

这里直接调用的是 HashMap 的构造方法(联系到前面学习的HashMap)。

由 HashSet 的成员变量和构造方法可以看出,HashSet 本质还是在内部维护一个 HashMap 对象,将所有的数据都交给 HashMap 进行处理。

成员方法

新增元素 add

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

将指定元素存入 HashSet,内部实现就是将指定元素作为 key,用常量对象 PRESENT 作为 value 存入 HashMap。

删除元素 remove

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

从集合中删除指定的元素,如果集合包含指定的元素,则返回 true。同样调用的 HashMap 的 remove 方法。

是否包含元素 contains

public boolean contains(Object o) {
    return map.containsKey(o);
}

contains 方法的目的是检查 HashSet 中是否存在元素。如果找到该元素,则返回 true,否则返回 false。本质上调用的 HashMap 的 containsKey 方法。

集合大小 size

public int size() {
    return map.size();
}

调用 HashMap 的 size 方法,返回当前集合的大小。

HashSet 是否是空的 isEmpty

public boolean isEmpty() {
    return map.isEmpty();
}

调用 HashMap 的 isEmpty 方法,判断当前集合是否是空的。

清空元素 clear

public void clear() {
    map.clear();
}

调用 HashMap 的 clear 方法,将当前集合清空。原理是遍历 HashMap 中的桶数组,将桶中的每个位置置为 null(联系到前面学习的HashMap)。

遍历 HashSet

获取迭代器 iterator

public Iterator<E> iterator() {
    return map.keySet().iterator();
}

本质上获取到的是内部维护的 map 的 keySet(键集)的迭代器对象。

LinkedHashSet

LinkedHashSet 是 HashSet 的子类,通过源码发现它是一个空壳,构造方法都调用 HashSet 的一个 default (没有使用访问修饰符修饰)构造方法 通过 HashSet 的这个 default 构造方法可知,LinkedHashSet 也是在 LinkedHashMap 基础之上包装了一层。

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

线程安全的使用

使用 Colletcions 这个工具类的 synchronizedSet 方法类创建个线程安全的 Set 集合。

public class HelloWorld {
    public static void main(String[] args) {
        HashSet<Object> hashSet = new HashSet<>();
        Set<Object> synchronizedSet = Collections.synchronizedSet(hashSet);
    }
}

笔记大部分摘录自《Java核心技术卷I》,含有少数本人修改补充痕迹。

参考文章:http://985.so/mmhca


 

相关文章
|
11天前
|
机器学习/深度学习 人工智能 自然语言处理
AI技术深度解析:从基础到应用的全面介绍
人工智能(AI)技术的迅猛发展,正在深刻改变着我们的生活和工作方式。从自然语言处理(NLP)到机器学习,从神经网络到大型语言模型(LLM),AI技术的每一次进步都带来了前所未有的机遇和挑战。本文将从背景、历史、业务场景、Python代码示例、流程图以及如何上手等多个方面,对AI技术中的关键组件进行深度解析,为读者呈现一个全面而深入的AI技术世界。
71 10
|
4天前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
1天前
|
安全 API 数据安全/隐私保护
速卖通AliExpress商品详情API接口深度解析与实战应用
速卖通(AliExpress)作为全球化电商的重要平台,提供了丰富的商品资源和便捷的购物体验。为了提升用户体验和优化商品管理,速卖通开放了API接口,其中商品详情API尤为关键。本文介绍如何获取API密钥、调用商品详情API接口,并处理API响应数据,帮助开发者和商家高效利用这些工具。通过合理规划API调用策略和确保合法合规使用,开发者可以更好地获取商品信息,优化管理和营销策略。
|
1天前
|
Java 数据库连接 Spring
反射-----浅解析(Java)
在java中,我们可以通过反射机制,知道任何一个类的成员变量(成员属性)和成员方法,也可以堆任何一个对象,调用这个对象的任何属性和方法,更进一步我们还可以修改部分信息和。
|
4天前
|
安全 算法 Java
Java CAS原理和应用场景大揭秘:你掌握了吗?
CAS(Compare and Swap)是一种乐观锁机制,通过硬件指令实现原子操作,确保多线程环境下对共享变量的安全访问。它避免了传统互斥锁的性能开销和线程阻塞问题。CAS操作包含三个步骤:获取期望值、比较当前值与期望值是否相等、若相等则更新为新值。CAS广泛应用于高并发场景,如数据库事务、分布式锁、无锁数据结构等,但需注意ABA问题。Java中常用`java.util.concurrent.atomic`包下的类支持CAS操作。
23 2
|
22天前
|
机器学习/深度学习 搜索推荐 API
淘宝/天猫按图搜索(拍立淘)API的深度解析与应用实践
在数字化时代,电商行业迅速发展,个性化、便捷性和高效性成为消费者新需求。淘宝/天猫推出的拍立淘API,利用图像识别技术,提供精准的购物搜索体验。本文深入探讨其原理、优势、应用场景及实现方法,助力电商技术和用户体验提升。
|
24天前
|
存储 算法 Java
Java内存管理深度解析####
本文深入探讨了Java虚拟机(JVM)中的内存分配与垃圾回收机制,揭示了其高效管理内存的奥秘。文章首先概述了JVM内存模型,随后详细阐述了堆、栈、方法区等关键区域的作用及管理策略。在垃圾回收部分,重点介绍了标记-清除、复制算法、标记-整理等多种回收算法的工作原理及其适用场景,并通过实际案例分析了不同GC策略对应用性能的影响。对于开发者而言,理解这些原理有助于编写出更加高效、稳定的Java应用程序。 ####
|
24天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
SQL 存储 Java
Java 应用与数据库的关系| 学习笔记
快速学习 Java 应用与数据库的关系。
209 0
Java 应用与数据库的关系| 学习笔记
|
SQL 存储 Java
Java 应用与数据库的关系| 学习笔记
快速学习 Java 应用与数据库的关系。
198 0
Java 应用与数据库的关系| 学习笔记

热门文章

最新文章

推荐镜像

更多