Java面试题5:List、Set、Map 的区别?各自有哪些实现类?

核心区别

  1. List (列表)
    • 核心特性:有序集合,允许重复元素。
    • 行为: 用户可以根据元素的整数索引(位置)访问元素。可以精确控制每个元素在列表中的位置。支持在指定位置插入和删除元素。
    • 典型实现: ArrayList, LinkedList, Vector。
  2. Set (集合)
    • 核心特性:无序集合,不允许重复元素(唯一性)。
    • 行为: 不保证元素的顺序(某些特定实现如 LinkedHashSet 或 TreeSet 会维护某种顺序)。最重要的操作是检查一个元素是否存在于集合中(contains)。
    • 典型实现: HashSet, LinkedHashSet, TreeSet。
  3. Map (映射)
    • 核心特性:键值对(Key-Value Pair)的集合。键(Key)唯一,值(Value)可重复。
    • 行为: 通过键来访问值。一个映射不能包含重复的键。每个键最多只能映射到一个值。
    • 典型实现: HashMap, LinkedHashMap, TreeMap, Hashtable。

简单对比表:

接口 元素特性 顺序保证 元素唯一性 访问方式
List 单个对象 有序 可重复 索引 (get(int))
Set 单个对象 无序 唯一 元素本身
Map 键值对 (K, V) 键无序/有序 键唯一 键 (get(K))

主要实现类

  1. List 实现类
    • ArrayList
      • 底层: 基于动态数组实现。
      • 特点:
        • 支持随机访问(通过索引快速访问元素,时间复杂度 O(1))。
        • 在列表尾部插入和删除元素效率较高(接近 O(1))。
        • 在列表中间插入和删除元素效率较低(需要移动元素,时间复杂度 O(n))。
        • 非线程安全。
    • LinkedList
      • 底层: 基于双向链表实现。
      • 特点:
        • 不支持高效的随机访问(需要遍历链表,时间复杂度 O(n))。
        • 在任意位置插入和删除元素效率较高(时间复杂度 O(1),只需修改节点指针)。
        • 实现了 Deque 接口,可用作队列或双端队列。
        • 非线程安全。
    • Vector
      • 底层: 基于动态数组实现。
      • 特点:
        • 是 Java 早期集合类。
        • 所有方法默认使用 synchronized 修饰,是线程安全的。
        • 性能通常不如 ArrayList(因为同步开销)。
        • 有一个子类 Stack(栈)。
  2. Set 实现类
    • HashSet
      • 底层: 基于 HashMap 实现(值存储在一个 HashMap 的键上)。
      • 特点:
        • 无序(不保证迭代顺序)。
        • 添加、删除、判断元素是否存在(contains)效率很高(时间复杂度接近 O(1))。
        • 非线程安全。
    • LinkedHashSet
      • 底层: 继承自 HashSet,内部使用 LinkedHashMap 实现。
      • 特点:
        • 维护了一个双向链表来记录元素的插入顺序。
        • 迭代时按照元素的插入顺序访问。
        • 性能略低于 HashSet(因为要维护链表)。
        • 非线程安全。
    • TreeSet
      • 底层: 基于 TreeMap 实现(值存储在一个 TreeMap 的键上)。
      • 特点:
        • 元素会根据自然排序 或指定的 Comparator 进行排序。
        • 迭代时按照排序后的顺序访问。
        • 添加、删除、判断元素是否存在(contains)基于红黑树,时间复杂度为 O(\\log n)。
        • 非线程安全。
  3. Map 实现类
    • HashMap
      • 底层: 基于哈希表(数组+链表/红黑树)实现。
      • 特点:
        • 键无序(不保证迭代顺序)。
        • 添加、删除、获取键值对效率很高(时间复杂度接近 O(1))。
        • 允许 null 作为键和值。
        • 非线程安全。
      • 重要: JDK 1.8 引入了链表长度超过阈值转红黑树的优化。
    • LinkedHashMap
      • 底层: 继承自 HashMap,内部维护了一个双向链表。
      • 特点:
        • 可以维护键的插入顺序 或访问顺序(LRU 缓存常用)。
        • 迭代时按照链表的顺序访问(插入顺序或访问顺序)。
        • 性能略低于 HashMap(因为要维护链表)。
        • 非线程安全。
    • TreeMap
      • 底层: 基于红黑树(一种自平衡二叉搜索树)实现。
      • 特点:
        • 键会根据自然排序 或指定的 Comparator 进行排序。
        • 迭代时按照键排序后的顺序访问。
        • 添加、删除、获取键值对基于红黑树,时间复杂度为 O(\\log n)。
        • 不允许 null 作为键(如果使用自然排序)。
        • 非线程安全。
    • Hashtable
      • 底层: 基于哈希表实现。
      • 特点:
        • 是 Java 早期集合类,与 Vector 类似。
        • 所有方法默认使用 synchronized 修饰,是线程安全的。
        • 性能通常不如 HashMap(因为同步开销)。
        • 不允许 null 作为键或值。
        • 现在通常更推荐使用 ConcurrentHashMap 替代它来实现线程安全。

线程安全注意事项

  • ArrayList, LinkedList, HashSet, LinkedHashSet, TreeSet, HashMap, LinkedHashMap, TreeMap 都是非线程安全的。
  • Vector, Hashtable 是线程安全的(但通常性能较低)。
  • 对于 List 和 Set,可以使用 Collections.synchronizedList() 或 Collections.synchronizedSet() 包装非线程安全的集合来获得线程安全版本。
  • 对于 Map,可以使用 Collections.synchronizedMap() 包装非线程安全的 Map,或者更推荐使用 ConcurrentHashMap(它是专门设计的高并发 Map 实现)。
相关推荐
从琳开始9894 分钟前
从Socket到UDP回显服务器:Java网络编程完整指南
java·网络·网络协议·udp·java-ee
ShineWinsu25 分钟前
对于Qt:QPushButton常见属性的解析
开发语言·c++·qt·api·gui·按钮·qpushbutton
外贸GEO优化26 分钟前
外贸独立站的可抓取性:JS 渲染、懒加载与无限滚动到底影响什么
开发语言·javascript·ecmascript
飞浪纪元[FWC–FE]27 分钟前
Qt 工程创建与 CMake / qmake 构建规范
开发语言·数据库·qt
后台模板学习39 分钟前
Go Web开发中任务调度框架的源码解析与高可用实现方案
开发语言·后端·golang
西瓜拿铁好喝42 分钟前
开源和闭源 AI 办公工具,分别适合谁
java·前端·数据库
学长毕设44 分钟前
基于SpringBoot的校园礼服租赁系统的设计与实现
java·spring boot·后端
明天也要努力学习1 小时前
深入理解 JVM 垃圾回收(GC)
java·jvm
xiaoye-duck1 小时前
《C++ 项目:手写大模型接入 SDK》DeepSeek接口设计(上):初始化和全量响应
开发语言·网络·c++·语言模型