砍材农夫砍材农夫
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • nodejs
    • npm
    • webpack
    • 微信
    • 正则
    • uniapp
  • java

    • java基础
    • jdk体系
    • jvm
    • spring
    • spring_cloud
    • spring_boot
    • 分库分表
    • zookeeper
  • python

    • python基础
    • python高级
    • python框架
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • docker
  • k8s
  • devops
  • nginx
  • 元宇宙
  • 区块链
  • 物联网
  • linux
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • nodejs
    • npm
    • webpack
    • 微信
    • 正则
    • uniapp
  • java

    • java基础
    • jdk体系
    • jvm
    • spring
    • spring_cloud
    • spring_boot
    • 分库分表
    • zookeeper
  • python

    • python基础
    • python高级
    • python框架
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • docker
  • k8s
  • devops
  • nginx
  • 元宇宙
  • 区块链
  • 物联网
  • linux
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • 首页
  • 基础

    • map循环
    • 委托
    • 泛型
    • 线程池
    • String 为什么不可变?面试必问
    • Java 异常处理最佳实践,别再乱用 try-catch
    • 为什么禁止在for循环里使用+拼接字符串
    • HashMap底层原理面试必背精简版
    • HashSet、LinkedHashSet、TreeSet 区别与使用场景
    • Java创建线程的3种方式简单易懂
    • 如何使用 jstack 排查死锁
  • 1. 对比概览
  • 2. 详细解析
    • 2.1 HashSet
    • 2.2 LinkedHashSet
    • 2.3 TreeSet
  • 3. 代码示例
    • 3.1 基本用法与顺序区别
    • 3.2 自定义排序(TreeSet)
  • 4. 选型建议
  • 5. 注意事项

在 Java 中,HashSet、LinkedHashSet 和 TreeSet 都是 Set 接口的实现类,它们都不允许存储重复元素。但它们底层的实现机制不同,导致在有序性、性能以及使用场景上有所区别。

以下是它们的详细对比与使用建议(Markdown 格式):


1. 对比概览

特性HashSetLinkedHashSetTreeSet
底层数据结构哈希表(HashMap)哈希表 + 双向链表(LinkedHashMap)红黑树(TreeMap)
是否允许 null允许(一个)允许(一个)不允许(若基于自然顺序或比较器,null 会引发 NPE)
有序性无序插入顺序(按元素插入的顺序迭代)排序顺序(自然排序或自定义排序)
线程安全非线程安全非线程安全非线程安全
时间复杂度add、remove、contains 为 O(1)add、remove、contains 为 O(1)add、remove、contains 为 O(log n)
内存占用较低较高(维护额外的链表)较高(维护红黑树结构)

2. 详细解析

2.1 HashSet

  • 特点:基于 HashMap 实现,元素无序存储。它依靠 hashCode() 和 equals() 方法保证元素的唯一性。
  • 优点:性能最高(常数时间),适合快速增删改查。
  • 缺点:迭代顺序不确定,且可能随时间变化(尤其是扩容后)。
  • 适用场景:
    • 只需要去重,不关心元素的顺序。
    • 对性能要求较高,且不需要排序或保持插入顺序的场景。

2.2 LinkedHashSet

  • 特点:继承自 HashSet,底层使用 LinkedHashMap 维护一个双向链表,记录元素的插入顺序。
  • 优点:既能保证唯一性,又能按插入顺序迭代。
  • 缺点:比 HashSet 略慢,内存开销略大(因为维护链表)。
  • 适用场景:
    • 需要维护元素的插入顺序(例如:保持缓存或队列的顺序)。
    • 需要更可预测的迭代顺序,但无需排序。

2.3 TreeSet

  • 特点:基于 TreeMap(红黑树)实现,元素默认按照自然顺序(Comparable)或构造时传入的 Comparator 进行排序。
  • 优点:元素始终处于排序状态,支持范围查找(如 subSet、headSet、tailSet)。
  • 缺点:性能较低(对数时间),不允许插入 null(因为在比较时无法处理 null)。
  • 适用场景:
    • 需要元素自动排序(如输出按字母顺序、数字大小顺序)。
    • 需要执行范围查询操作。

3. 代码示例

3.1 基本用法与顺序区别

import java.util.*;

public class SetDemo {
    public static void main(String[] args) {
        // 1. HashSet
        Set<String> hashSet = new HashSet<>();
        hashSet.add("Banana");
        hashSet.add("Apple");
        hashSet.add("Cherry");
        System.out.println("HashSet: " + hashSet); 
        // 输出无序,例如: [Apple, Banana, Cherry] 或 [Banana, Apple, Cherry]

        // 2. LinkedHashSet
        Set<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("Banana");
        linkedHashSet.add("Apple");
        linkedHashSet.add("Cherry");
        System.out.println("LinkedHashSet: " + linkedHashSet); 
        // 输出: [Banana, Apple, Cherry] (保持插入顺序)

        // 3. TreeSet
        Set<String> treeSet = new TreeSet<>();
        treeSet.add("Banana");
        treeSet.add("Apple");
        treeSet.add("Cherry");
        System.out.println("TreeSet: " + treeSet); 
        // 输出: [Apple, Banana, Cherry] (按字母排序)
    }
}

3.2 自定义排序(TreeSet)

// 降序排序示例
Set<Integer> treeSet = new TreeSet<>(Collections.reverseOrder());
treeSet.add(5);
treeSet.add(1);
treeSet.add(3);
System.out.println(treeSet); // 输出: [5, 3, 1]

4. 选型建议

场景推荐集合
单纯的去重,对顺序无要求,追求最高性能HashSet
需要按照元素添加的顺序进行遍历(如 LRU 缓存、队列去重)LinkedHashSet
需要元素自动排序,或者需要范围查询(如排行榜、有序字典)TreeSet
在单线程环境下,以上三者均不安全,若需线程安全可使用 Collections.synchronizedSet() 或 ConcurrentSkipListSet(替代 TreeSet)-

5. 注意事项

  1. 重写 hashCode 和 equals:使用 HashSet 或 LinkedHashSet 存储自定义对象时,必须正确重写这两个方法,否则会导致去重失效。
  2. TreeSet 的比较逻辑:
    • 如果元素实现 Comparable 接口,使用自然排序。
    • 如果未实现,必须在构造 TreeSet 时传入 Comparator,否则会抛出 ClassCastException。
    • 禁止插入 null,因为在排序过程中会调用 compareTo 方法,导致空指针异常。
  3. 性能权衡:虽然 TreeSet 提供了排序功能,但增删改查的时间复杂度为 O(log n),在数据量极大且对排序无硬性要求时,应优先考虑 HashSet。

通过以上对比,你可以根据实际业务需求(是否需要顺序、是否需要排序、性能要求)来选择合适的 Set 实现。

最近更新: 2026/3/30 13:25
Contributors: kcnf
Prev
HashMap底层原理面试必背精简版
Next
Java创建线程的3种方式简单易懂