Java 集合--快速掌握涵盖三大场景实现的Set集合底层原理

发布时间:2026/7/30 8:50:27

Java 集合--快速掌握涵盖三大场景实现的Set集合底层原理
Java 集合–快速掌握涵盖三大场景实现的Set集合底层原理引言在 Java 集合框架中Set接口是一个不允许包含重复元素的集合。与List不同Set没有索引概念元素存取无序。虽然Set看似简单但其底层实现却涉及多种数据结构以适应不同场景的需求。本文将深入剖析HashSet、TreeSet和LinkedHashSet这三大经典实现的底层原理并通过实战代码演示帮助开发者快速掌握其核心机制。—## 一、HashSet基于哈希表的快速查找### 1.1 底层数据结构HashSet底层实际上是一个HashMap的实例。当我们向HashSet添加元素时实际上是将该元素作为HashMap的 key 存入而 value 则是一个固定的常量对象PRESENT。这种设计使得HashSet能充分利用HashMap的哈希算法实现 O(1) 时间复杂度的增删改查。### 1.2 哈希冲突处理当两个不同的元素通过hashCode()计算得到相同的哈希桶索引时就会发生哈希冲突。HashSet采用链地址法数组链表/红黑树来解决冲突当链表长度超过阈值默认为8且数组长度大于64时链表会转换为红黑树以提升查找性能。### 1.3 实战代码示例javaimport java.util.HashSet;import java.util.HashMap;public class HashSetDemo { public static void main(String[] args) { // 创建HashSet实例 HashSetString set new HashSet(); // 添加元素 set.add(Apple); set.add(Banana); set.add(Cherry); set.add(Apple); // 重复元素不会添加成功 // 输出集合大小 System.out.println(集合大小: set.size()); // 输出 3 // 检查元素是否存在 System.out.println(包含Apple? set.contains(Apple)); // true // 遍历集合无序 for (String fruit : set) { System.out.println(水果: fruit); } // 底层原理验证HashSet实际上是一个HashMap // 通过反射获取内部map try { java.lang.reflect.Field mapField HashSet.class.getDeclaredField(map); mapField.setAccessible(true); HashMapString, Object internalMap (HashMapString, Object) mapField.get(set); System.out.println(内部HashMap容量: internalMap.size()); // 3 } catch (Exception e) { e.printStackTrace(); } }}输出说明由于HashSet基于哈希表元素输出顺序与插入顺序无关且重复元素被自动过滤。—## 二、TreeSet基于红黑树的有序集合### 2.1 底层数据结构TreeSet底层是一个TreeMap红黑树结构它要求元素必须实现Comparable接口或者在构造时传入一个Comparator比较器。红黑树是一种自平衡的二叉搜索树能够保证所有操作增删改查的时间复杂度为 O(log n)并且元素会按照自然顺序或比较器定义的顺序排序。### 2.2 排序机制TreeSet在插入元素时会通过红黑树的节点比较逻辑确定元素位置。如果自定义对象未实现Comparable且未提供比较器则会抛出ClassCastException。### 2.3 实战代码示例javaimport java.util.TreeSet;import java.util.Comparator;public class TreeSetDemo { public static void main(String[] args) { // 创建一个按字母逆序排序的TreeSet TreeSetString treeSet new TreeSet(Comparator.reverseOrder()); treeSet.add(Charlie); treeSet.add(Alice); treeSet.add(Bob); treeSet.add(David); // 输出有序集合逆序 System.out.println(逆序排序结果:); for (String name : treeSet) { System.out.println(name); // David, Charlie, Bob, Alice } // 使用自定义对象必须实现Comparable TreeSetPerson personSet new TreeSet(); personSet.add(new Person(张三, 25)); personSet.add(new Person(李四, 30)); personSet.add(new Person(王五, 20)); System.out.println(\n按年龄排序的人员:); for (Person p : personSet) { System.out.println(p); } // 获取第一个和最后一个元素 System.out.println(最年轻的人: personSet.first()); // 王五 System.out.println(最年长的人: personSet.last()); // 李四 }}// 自定义Person类实现Comparable接口class Person implements ComparablePerson { private String name; private int age; public Person(String name, int age) { this.name name; this.age age; } Override public int compareTo(Person other) { // 按年龄升序排序 return this.age - other.age; } Override public String toString() { return name ( age 岁); }}关键点TreeSet通过红黑树维护元素顺序自定义对象必须提供比较逻辑否则无法正常工作。—## 三、LinkedHashSet结合哈希表与双向链表### 3.1 底层数据结构LinkedHashSet继承自HashSet但其内部使用LinkedHashMap而不是普通的HashMap。LinkedHashMap在HashMap的基础上增加了一个双向链表用于维护元素的插入顺序或访问顺序。因此LinkedHashSet既能保证元素的唯一性通过哈希表又能保持迭代顺序与插入顺序一致。### 3.2 性能特点-插入性能接近HashSet的 O(1) 时间复杂度但维护链表会带来额外的内存开销。-迭代性能由于链表的存在LinkedHashSet的迭代速度通常比HashSet更快因为它只需要遍历链表而HashSet需要遍历整个哈希桶数组。### 3.3 实战代码示例javaimport java.util.LinkedHashSet;public class LinkedHashSetDemo { public static void main(String[] args) { // 创建LinkedHashSet LinkedHashSetString linkedSet new LinkedHashSet(); // 添加元素 linkedSet.add(第一); linkedSet.add(第二); linkedSet.add(第三); linkedSet.add(第二); // 重复不会添加 // 输出结果保持插入顺序 System.out.println(LinkedHashSet遍历保持插入顺序:); for (String item : linkedSet) { System.out.println(item); } // 输出: 第一, 第二, 第三 // 对比HashSet无序 java.util.HashSetString hashSet new java.util.HashSet(); hashSet.add(第一); hashSet.add(第二); hashSet.add(第三); System.out.println(\nHashSet遍历无序:); for (String item : hashSet) { System.out.println(item); } // 性能测试插入大量数据 long startTime System.nanoTime(); LinkedHashSetInteger largeLinkedSet new LinkedHashSet(); for (int i 0; i 100000; i) { largeLinkedSet.add(i); } long endTime System.nanoTime(); System.out.println(\nLinkedHashSet插入10万元素耗时: (endTime - startTime) / 1_000_000 ms); }}运行结果分析LinkedHashSet保证了元素的插入顺序而HashSet则完全无序。虽然维护链表会稍有性能损耗但在大多数场景下可以忽略不计。—## 四、三大Set实现对比总结| 特性 | HashSet | TreeSet | LinkedHashSet ||------|---------|---------|---------------|| 底层结构 | HashMap数组链表/红黑树 | TreeMap红黑树 | LinkedHashMapHashMap双向链表 || 元素顺序 | 无序 | 自然顺序或自定义顺序 | 插入顺序 || 时间复杂度 | O(1) 平均 | O(log n) | O(1) 平均 || 是否允许null | 允许一个null | 不允许需比较 | 允许一个null || 适用场景 | 快速查找、去重 | 需要排序的集合 | 需要保持插入顺序且去重 |—## 五、选择指南-追求极致性能选择HashSet适合大数据量且不关心顺序的场景。-需要自动排序选择TreeSet适合需要范围查询或有序遍历的场景如排行榜。-需要保持插入顺序选择LinkedHashSet适合需要记录操作顺序的去重场景如最近访问记录。—## 总结本文通过大量实战代码演示深入分析了HashSet、TreeSet和LinkedHashSet的底层实现原理。HashSet基于哈希表实现快速查找TreeSet基于红黑树实现自动排序LinkedHashSet则通过哈希表与双向链表的结合在保持元素唯一性的同时维护了插入顺序。理解这些底层机制有助于我们在实际开发中根据具体场景选择最合适的Set实现从而优化程序性能和代码可读性。记住没有绝对的最优只有最适合场景的选择。

相关新闻

Visual Studio远程开发Linux C++项目:配置、调试与实战指南

Visual Studio远程开发Linux C++项目:配置、调试与实战指南

2026/7/30 8:50:27

1. 项目概述:为什么要在Windows上用VS搞Linux开发?如果你是一个长期在Windows环境下使用Visual Studio(后面简称VS)的C开发者,现在因为项目需求,必须将代码部署到Linux服务器上运行,那你大概率会…

构建长期可维护的数字项目:工程化实践与可持续性方法论

构建长期可维护的数字项目:工程化实践与可持续性方法论

2026/7/30 8:40:27

那天下午,我偶然点开一个动画片段:一位龙族少女,独自守着一座空寂了数万年的神殿。弹幕里飘过一句:“她等的那个勇者,是不是早就忘了登录密码?” 这句玩笑背后,其实藏着一个很多内容创作者和技术…

TPM密钥层次结构解析:从BitLocker到虚拟化的安全基石

TPM密钥层次结构解析:从BitLocker到虚拟化的安全基石

2026/7/30 8:40:27

1. 从一次“密钥丢失”事件说起:为什么需要理解TPM密钥架构 最近在排查一个生产环境的问题时,遇到了一个典型的场景:一台启用了BitLocker的服务器主板故障,更换后系统无法启动,提示需要BitLocker恢复密钥。虽然最终用4…

Python数据分析实战:缺失值检测与处理的完整指南

Python数据分析实战:缺失值检测与处理的完整指南

2026/7/30 10:00:30

1. 项目概述:为什么缺失值处理是数据分析的“必修课” 做数据分析,尤其是用Python,你迟早会碰到一堆带着NaN(Not a Number)或者空格的表格。这玩意儿叫缺失值,它就像你精心准备的食材里混进了一颗坏掉的土豆…

WeChatExporter技术架构解析:微信聊天记录导出工具的设计与实现

WeChatExporter技术架构解析:微信聊天记录导出工具的设计与实现

2026/7/30 10:00:30

WeChatExporter技术架构解析:微信聊天记录导出工具的设计与实现 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter WeChatExporter是一款基于Node.js和AngularJS…

Commvault进化论:从备份软件到智能数据管理平台的实战解析

Commvault进化论:从备份软件到智能数据管理平台的实战解析

2026/7/30 10:00:30

1. 项目概述:当老牌备份巨头开始“玩”新花样 在数据管理这个看似传统、甚至有些“沉闷”的领域里,Commvault这个名字,对于任何一位超过五年经验的IT运维或数据保护工程师来说,都意味着一个绕不开的“巨无霸”。它就像数据备份界的…

采集换热器温度数据,计算换热效率,对比理论值,自动标记换热效能衰减设备。

采集换热器温度数据,计算换热效率,对比理论值,自动标记换热效能衰减设备。

2026/7/30 10:00:30

换热器热效率监测与衰减分析系统 —— 基于OOP的工业数据实战"一台换热器的寿命,写在K值衰减曲线里;而工程师的责任,是在它跌破红线之前读懂这条曲线。"—— 哈尔滨工程大学《工业过程控制》课程核心思想一、实际应用场景描述在石油…

基于 llama.cpp 的 VLM 推理系统:CPU 隔离与实时优先级保护实战

基于 llama.cpp 的 VLM 推理系统:CPU 隔离与实时优先级保护实战

2026/7/30 10:00:30

1. 引言 本文基于 ROS2 Jazzy 和 llama.cpp,设计并实现了一个完整的 VLM 推理封装包 vlm_inference_cpu_isolation。该系统通过 CPU 核心隔离、实时线程优先级保护、GPU/CPU 双模式切换等技术手段,实现了在资源受限平台上的高效、可靠 VLM 推理。同时探…

网络协议分析实战:从ARP到IP转发,掌握Wireshark抓包与故障排查

网络协议分析实战:从ARP到IP转发,掌握Wireshark抓包与故障排查

2026/7/30 9:50:29

1. 项目概述:从“看热闹”到“看门道”的网络协议分析如果你学计算机网络,还停留在背概念、记协议头的阶段,那感觉就像学开车只背交规,从来没摸过方向盘。网络层和链路层协议分析这个实验,就是让你真正“上路”的第一次…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/30 9:53:22

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/7/30 1:17:46

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/7/30 2:52:37

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…

粉笔直播课适合周末集中备考考生突破吗

粉笔直播课适合周末集中备考考生突破吗

2026/7/30 0:09:54

本文面向在职备考、工作日难以抽出整块时间、只能依靠周末集中复习的公考考生,围绕"该平台直播课是否适配周末集中备考节奏、能否支撑瓶颈突破"这一核心问题做客观拆解。文中数据来源于公开财报、官网公示价格、第三方投诉平台公开投诉及用户社区讨论&…

ThreadLocal(存取变量)实战获取当前登录的员工

ThreadLocal(存取变量)实战获取当前登录的员工

2026/7/30 0:09:54

注意AOP所应用的注解以及service方法上自定义的Log注解

INAV飞控配置终极指南:从零到稳定飞行的完整解决方案

INAV飞控配置终极指南:从零到稳定飞行的完整解决方案

2026/7/30 0:09:54

INAV飞控配置终极指南:从零到稳定飞行的完整解决方案 【免费下载链接】inav INAV: Navigation-enabled flight control software 项目地址: https://gitcode.com/gh_mirrors/in/inav INAV飞控配置是每个无人机爱好者必须掌握的核心技能,但很多新手…