java-hashset 源码分析 3

### 9. `HashSet` 的局限性

#### 9.1 无序性

`HashSet` 不保证元素的顺序,这意味着插入顺序和遍历顺序可能不同。如果需要有序集合,可以考虑使用 `LinkedHashSet` 或 `TreeSet`。

#### 9.2 性能依赖于哈希函数

`HashSet` 的性能高度依赖于哈希函数的质量。如果哈希函数不均匀地分布元素,可能会导致大量哈希冲突,降低性能。

### 10. `HashSet` 的替代方案

#### 10.1 `LinkedHashSet`

`LinkedHashSet` 是 `HashSet` 的一个子类,除了提供 `HashSet` 的所有功能外,还维护了元素的插入顺序。因此,`LinkedHashSet` 适用于需要保持元素顺序的场景。

```java
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetExample {
    public static void main(String[] args) {
        Set<String> set = new LinkedHashSet<>();
        set.add("apple");
        set.add("banana");
        set.add("cherry");

        System.out.println("LinkedHashSet: " + set);
    }
}
```

#### 10.2 `TreeSet`

`TreeSet` 实现了 `NavigableSet` 接口,基于红黑树实现,保证元素的自然顺序或通过 `Comparator` 定制的顺序。`TreeSet` 适用于需要排序功能的场景。

```java
import java.util.Set;
import java.util.TreeSet;

public class TreeSetExample {
    public static void main(String[] args) {
        Set<String> set = new TreeSet<>();
        set.add("banana");
        set.add("apple");
        set.add("cherry");

        System.out.println("TreeSet: " + set);
    }
}
```

### 11. `HashSet` 源码中的优化技巧

#### 11.1 高效的哈希冲突处理

`HashSet` 通过 `HashMap` 来处理哈希冲突,使用链地址法(即在数组的每个位置存储一个链表或红黑树)。这种方法能够有效地处理哈希冲突,特别是在元素数量较大时。

#### 11.2 动态扩容

`HashSet` 通过 `HashMap` 的动态扩容机制来保持较低的负载因子,从而提高查询和插入操作的效率。`HashMap` 在容量达到阈值时会自动扩容,并重新散列所有元素。

### 12. `HashSet` 的设计与实现

`HashSet` 的设计与实现主要依赖于 `HashMap`,通过对 `HashMap` 的封装,提供了集合的功能。`HashSet` 的源码设计体现了良好的代码复用和模块化设计原则。

#### 12.1 简化的设计

通过将所有元素存储在 `HashMap` 的键中,`HashSet` 避免了重复实现哈希表的复杂逻辑。`HashMap` 的键唯一性保证了 `HashSet` 中元素的唯一性,而 `PRESENT` 常量则简化了 `HashMap` 的值管理。

#### 12.2 扩展性

`HashSet` 的设计允许其轻松扩展。例如,`LinkedHashSet` 通过继承 `HashSet` 并使用 `LinkedHashMap` 作为底层实现,增加了对插入顺序的维护功能。

### 13. 源码分析示例

下面是 `HashSet` 的完整源码示例,展示了其内部实现细节。

```java
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;

    private static final Object PRESENT = new Object();

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

    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);
    }

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

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

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

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

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

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

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

    @Override
    public Object clone() {
        try {
            HashSet<E> newSet = (HashSet<E>) super.clone();
            newSet.map = (HashMap<E, Object>) map.clone();
            return newSet;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }

    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        s.defaultWriteObject();
        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());
        s.writeInt(map.size());
        for (E e : map.keySet())
            s.writeObject(e);
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        int capacity = s.readInt();
        float loadFactor = s.readFloat();
        int size = s.readInt();
        map = ((size >= 0) ? new HashMap<>(capacity, loadFactor) : new HashMap<>());
        for (int i = 0; i < size; i++) {
            @SuppressWarnings("unchecked")
            E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }
}
```

### 14. 总结

`HashSet` 是 Java 集合框架中的一个重要类,提供了基于哈希表的集合实现。通过详细分析 `HashSet` 的源码,可以更好地理解其内部机制和工作原理。`HashSet` 适用于需要确保元素唯一性和快速查找的场景。

通过深入了解 `HashSet` 的数据结构、构造方法、核心操作、内部实现机制、迭代器支持、序列化与克隆等,可以更有效地使用 `HashSet` 并优化程序性能。同时,了解其局限性和替代方案,有助于在不同应用场景中选择最合适的集合类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/42382.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网页生成二维码、在线演示

https://andi.cn/page/621504.html

【OJ】运行时错误(Runtime Error)导致递归爆栈问题

在进行OJ赛时&#xff0c; 题目&#xff1a;给你一个整数n&#xff0c;问最多能将其分解为多少质数的和。在第一行输出最多的质数数量k,下一行输出k个整数&#xff0c;为这些质数。 出现运行时错误 代码如下&#xff1a; def main():# code heren int(eval(input()))list …

《优化接口设计的思路》系列:第2篇—小程序性能优化

优化Uniapp应用程序的性能可以从以下几个方面进行优化&#xff1a; 1.减少页面加载时间&#xff1a;避免页面过多和过大的组件&#xff0c;减少不必要的资源加载。可以使用懒加载的方式&#xff0c;根据用户的实际需求来加载页面和组件。 2.节流和防抖&#xff1a;对于频繁触发…

AI中药处方模型构建与案例

在中医领域,人工智能(AI)可以生成各种指令来辅助诊断、治疗和研究。 1. 诊断辅助指令: 根据患者的症状和体征,自动分析并生成可能的中医证候诊断建议。利用中医望闻问切四诊信息,智能识别关键症状,提供对应的中医辨证思路。2. 治疗建议指令: 根据辨证结果,自动推荐相应…

力扣304.二维区域和检索

力扣304.二维区域和检索 二维前缀和的简单应用 class NumMatrix {vector<vector<int>> sum;public:NumMatrix(vector<vector<int>>& matrix) {int m matrix.size(),n matrix[0].size();sum.resize(m1,vector<int>(n1)); for(int i0;i&…

Java语言程序设计篇一

Java语言概述 Java语言起源编程语言最新排名名字起源Java语言发展历程Java语言的特点Java虚拟机垃圾回收Java语言规范Java技术简介Java程序的结构Java程序注意事项&#xff1a;注释编程风格练习 Java语言起源 1990年Sun公司提出一项绿色计划。1992年语言开发成功最初取名为Oak…

维护el-table列,循环生成el-table

1、lib/setting.js&#xff08;维护table列&#xff09; const columns[{ label: 类型, prop: energyName, width: 150, isText: true },{ label: 消耗量(t或10⁴m), prop: inputNum, isInput: true },{label: CO₂,children: [// { label: 核算因子, prop: co2FactorValue, w…

cs231n作业1——Softmax

参考文章&#xff1a;cs231n assignment1——softmax Softmax softmax其实和SVM差别不大&#xff0c;两者损失函数不同&#xff0c;softmax就是把各个类的得分转化成了概率。 损失函数&#xff1a; def softmax_loss_naive(W, X, y, reg):loss 0.0dW np.zeros_like(W)num_…

【Linux】进程的概念 + 查看进程

前言&#xff1a; 在前面我们学习了Liunx的基本指令和权限相关知识&#xff0c;还有基本工具的使用&#xff0c;有了以上的基础知识我们本章将正式接触Linux操作系统。 目录 1.冯诺依曼体系结构1.1 内存存在的意义1.2 程序加载到内存的含义1.3 程序的预加载&#xff1a; 2 .认识…

安卓备忘录App开发

安卓备忘录APP开发,文章末尾有源码和apk安装包 目标用户: 普通安卓手机用户,需要一个简单易用的备忘录App来记录和管理日常事务。 主要功能: 用户注册: 用户可以创建一个账号,输入用户名和密码。 用户登录: 用户可以通过用户名和密码登录到应用。 用户信息存储: 用户名和…

TCP一定可靠吗

背景 公司某个服务发送TCP报文后,得到的响应是非预期数据 原因竟然是:TCP包的 payload 数据某个bit位被翻转,但是 checksum 的值一样,错误的包被分发给了上层服务 Checksum介绍 IP 头有自己的 Checksum,TCP、UDP 也有自己的 Checksum,分别校验不同部分的数据 IP 头的 …

触摸与指针:深入探索 WebKit 的 Pointer Events 支持

触摸与指针&#xff1a;深入探索 WebKit 的 Pointer Events 支持 在现代 Web 应用中&#xff0c;用户交互的方式越来越多样化&#xff0c;包括触摸、鼠标、笔等多种输入设备。WebKit 作为领先的浏览器引擎之一&#xff0c;对指针事件&#xff08;Pointer Events&#xff09;的…

影响Mongodb数据写入性能的因素

学习mongodb&#xff0c;体会mongodb的每一个使用细节&#xff0c;欢迎阅读威赞的文章。这是威赞发布的第83篇mongodb技术文章&#xff0c;欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题&#xff0c;欢迎在文章下面点个赞&#xff0c;或者关…

Java面试之并发与网络通信常见面试题

并发编程部分 1. 什么是进程和线程&#xff1f; 进程&#xff1a;操作系统分配资源的最小单位&#xff0c;各个进程之间占据独立的寻址空间&#xff0c;运行也是独立运行&#xff0c;进程间通信需要一些机制。 线程&#xff1a;程序执行的基本单位&#xff0c;一个进程可以开…

android 7.0 tts文字转语音

支持中文的SDK 语音引擎下载 import android.content.Context; import android.speech.tts.TextToSpeech; import android.util.Log;import java.util.Locale;public class SystemTTS {private static final String TAG "SystemTTS";private static SystemTTS insta…

聚星文社一键生成工具绘唐3科技AI工具

聚星文社一键生成工具绘唐3科技AI工具 绘唐3.0——用户文档 - 飞书云文档 聚星文社一键生成工具绘唐3科技AI工具是一个基于人工智能技术的辅助创作工具&#xff0c;可以帮助用户快速生成有关唐朝科技的文本内容。该工具利用自然语言处理和机器学习等技术&#xff0c;通过输入一…

帕金森病患者在选择运动疗法时应该注意哪些事项?

帕金森病患者在选择运动疗法时&#xff0c;应该遵循以下几点注意事项&#xff1a; 个性化运动处方&#xff1a;根据患者的病情、年龄、健康状况、以往运动能力等因素&#xff0c;制定个体化的运动处方。 避免运动负荷过大&#xff1a;运动时间不宜过长&#xff0c;注意控制心率…

JavaWeb-【1】HTML

笔记系列持续更新,真正做到详细!!本次系列重点讲解后端,那么第一阶段先讲解前端 目录 1、Javaweb技术体系 2、BS架构说明 3、官方文档 4、网页组成 5、HTML 6、HTML快速入门 7、HTML基本结构 8、HTML标签 ​9、HTML标签使用细节 ①、font标签 ②、字符实体 ③、标…

SSM养老院管理系统-计算机毕业设计源码02221

摘要 本篇论文旨在设计和实现一个基于SSM的养老院管理系统&#xff0c;旨在提供高效、便捷的养老院管理服务。该系统将包括老人档案信息管理、护工人员管理、房间信息管理、费用管理等功能模块&#xff0c;以满足养老院管理者和居民的不同需求。 通过引入SSM框架&#x…

通过消息传递同步操作

通信顺序进程&#xff08;CSP&#xff09; 是一种形式语言&#xff0c;用来描述并发性系统间进行交互的模式 每个线程或进程独立运行&#xff0c;它们之间仅通过消息传递进行通信&#xff0c;而不是直接共享状态 每个线程实际上都是一个状态机&#xff1a;当它接收到一条消息时…