当前位置: 首页 > ds >正文

Java Set系列集合详解:HashSet、LinkedHashSet、TreeSet底层原理与使用场景

Java Set系列集合详解:HashSet、LinkedHashSet、TreeSet底层原理与使用场景


一、Set系列集合概述

1. 核心特点

  • 无序性:存取顺序不一致(LinkedHashSet除外)。
  • 唯一性:元素不重复。
  • 无索引:无法通过索引直接访问元素,不能使用普通for循环遍历。

2. 常见实现类

实现类特点底层数据结构
HashSet无序、唯一、无索引哈希表(数组+链表/红黑树)
LinkedHashSet有序(存取顺序一致)、唯一哈希表+双向链表
TreeSet可排序(自然或自定义)、唯一红黑树

二、Set接口常用方法

Set继承自Collection接口,常用方法如下:

方法说明
boolean add(E e)添加元素,成功返回true
void clear()清空集合
boolean remove(E e)删除指定元素
`boolean contains(Object)判断是否包含元素
int size()返回集合元素个数

三、各实现类详解

1. HashSet

底层原理
  • JDK8前:数组 + 链表。
  • JDK8后:数组 + 链表 + 红黑树(链表长度≥8且数组长度≥64时触发转换)。
  • 哈希值计算:通过重写hashCode()equals()保证元素唯一性。
扩容机制
  • 默认初始容量:16。
  • 加载因子:0.75(当元素数量达到容量的75%时触发扩容)。
代码示例
Set<String> set = new HashSet<>();
set.add("A");
set.add("A"); // 添加失败
System.out.println(set); // 输出无序,如 [A, B]

2. LinkedHashSet

核心特点
  • 继承自HashSet,通过双向链表维护插入顺序。
  • 性能略低于HashSet,但遍历效率更高。
代码示例
LinkedHashSet<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("B");
linkedSet.add("A");
System.out.println(linkedSet); // 输出顺序固定为 [B, A]

3. TreeSet

排序规则
  • 自然排序:元素需实现Comparable接口,重写compareTo()
  • 比较器排序:创建TreeSet时传入Comparator自定义规则。
代码示例
// 自然排序(按年龄升序)
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(new Student("Tom", 20));
treeSet.add(new Student("Alice", 18));
// 输出按年龄排序:Alice(18) → Tom(20)

四、补充知识点

1. 线程安全性

  • HashSetTreeSetLinkedHashSet非线程安全
  • 解决方案:使用Collections.synchronizedSet()包装。
Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());

2. 哈希冲突解决策略

  • 链地址法(HashSet采用):冲突元素以链表形式存储。
  • 开放寻址法:线性探测或二次探测。

3. 红黑树简介

  • 一种自平衡二叉查找树,保证插入、删除、查找的时间复杂度为O(log n)
  • 特性:节点颜色交替、根节点为黑、叶子节点为黑、任意路径黑节点数相同。

4. 性能对比

操作HashSetLinkedHashSetTreeSet
插入O(1)O(1)O(log n)
删除O(1)O(1)O(log n)
查询O(1)O(1)O(log n)
有序性插入顺序自然/自定义

五、应用场景总结

场景推荐集合
去重且无需顺序HashSet
去重且保留插入顺序LinkedHashSet
去重且需排序TreeSet
高频查询HashSet
需要线程安全Collections.synchronizedSet()

六、常见面试题

  1. HashSet如何保证元素唯一?
    通过hashCode()equals()方法:先比较哈希值,再通过equals判断内容是否相同。

  2. TreeSet两种排序方式如何选择?

    • 默认使用自然排序(需实现Comparable)。
    • 若类无法修改或需多规则排序,使用Comparator
  3. HashSet和HashMap的关系?
    HashSet底层基于HashMap实现,元素存储为HashMap的键(值固定为PRESENT占位对象)。


关注博主,获取更多Java集合框架深度解析!

http://www.xdnf.cn/news/6818.html

相关文章:

  • 产品经理入门——认识产品经理
  • OCCT知识笔记之Poly_Triangulation详解
  • YOLOv7训练时4个类别只出2个类别
  • vue使用Fabric和pdfjs完成合同签章及批注
  • 第八节第三部分:认识枚举、枚举的作用和应用场景
  • DeepSearch:WebThinker开启AI搜索研究新纪元!
  • 游戏站的几种形式
  • redis数据结构-11(了解 Redis 持久性选项:RDB 和 AOF)
  • STM32H743IIT6_ADC采集误差分析与ADC_DMA
  • 【论信息系统项目的整合管理】
  • leetcode 2900. 最长相邻不相等子序列 I 简单
  • 【LeetCode 热题 100】搜索插入位置 / 搜索旋转排序数组 / 寻找旋转排序数组中的最小值
  • 基于javaweb的SpringBoot驾校预约学习系统设计与实现(源码+文档+部署讲解)
  • Jenkins 安装与配置指南
  • A12 乐队指挥更懂管理
  • STM32 定时器主从模式配置解析
  • C++:单例模式
  • Day 22 训练
  • 01-多线程案例-线程安全问题
  • n8n 中文系列教程_23. 【实战篇】如何零成本搭建Deep Research类AI工具
  • MySQL8新特性
  • 【Vite】前端开发服务器的配置
  • 【Dv3Admin】插件 dv3admin_chatgpt 集成大语言模型智能模块
  • 深入理解 Git 分支操作的底层原理
  • 基于协同过滤的文学推荐系统设计【源码+文档+部署】
  • 机器学习第十五讲:决策树全面讲解:像玩“20个问题“游戏猜身份[特殊字符]
  • 逻辑复制环境删除订阅报错 replication slot does not exist
  • 源码与二进制包区别
  • foreach中使用await的问题
  • 【AI】用Dify实现一个模拟面试的功能