java8的集合和map

Java 8 集合与 Map 全览及原理

一、整体架构

                    Iterable
                      │
                    Collection                    Map
                   ╱    │    ╲                  ╱    ╲
                List  Set  Queue          SortedMap  ...
               ╱  ╲    │      ╲            │
          ArrayList  LinkedList  TreeSet  TreeMap
          Vector     HashSet     PriorityQueue
          Stack      LinkedHashSet
                    (CopyOnWriteArraySet)

二、List 系列(有序、可重复)

1. ArrayList

  • 底层数据结构:Object[] 数组
  • 原理:
    • 默认初始容量 10,按 1.5 倍扩容(oldCapacity + (oldCapacity >> 1))
    • 随机访问 get(i) 时间复杂度 O(1),通过数组下标直接定位
    • 头部插入/删除需要移动元素,O(n)
    • 尾部插入均摊 O(1)
    • 非线程安全

2. Vector

  • 底层数据结构:Object[] 数组
  • 原理:与 ArrayList 几乎相同,区别在于:
    • 所有公共方法加 synchronized,线程安全但性能差
    • 扩容默认 2 倍(可自定义增长系数)
    • 现已基本不使用,被 Collections.synchronizedList() 或 CopyOnWriteArrayList 替代

3. Stack

  • 底层数据结构:继承自 Vector 的数组
  • 原理:
    • LIFO(后进先出)栈结构
    • push() 尾部入栈,pop() 尾部出栈
    • 同样加 synchronized,线程安全但性能差
    • 官方推荐使用 Deque(如 ArrayDeque)替代

4. LinkedList

  • 底层数据结构:双向链表
  • 原理:
    • 每个节点保存 prev 和 next 两个指针
    • 随机访问需要从头/尾遍历,O(n)
    • 头尾插入/删除 O(1)(已知节点位置时)
    • 同时实现了 List 和 Deque 接口,可作为链表、队列、栈使用
    • 非线程安全

三、Set 系列(无序、不可重复)

1. HashSet

  • 底层数据结构:HashMap<E, Object>
  • 原理:
    • 内部用一个 HashMap,元素作为 key,value 固定为 PRESENT 常量
    • 去重依赖 hashCode() + equals()
    • 插入/删除/查找 平均 O(1),最坏 O(n)(哈希冲突严重时)
    • 无序,迭代顺序不确定
    • 允许一个 null 元素

2. LinkedHashSet

  • 底层数据结构:LinkedHashMap<E, Object>
  • 原理:
    • 继承 HashSet,内部使用 LinkedHashMap 存储
    • 在 HashMap 基础上维护了一条双向链表记录插入顺序
    • 迭代时按插入顺序返回
    • 性能略低于 HashSet(链表维护开销),但迭代性能更好

3. TreeSet

  • 底层数据结构:TreeMap<E, Object>
  • 原理:
    • 内部用 TreeMap,元素作为 key
    • 基于红黑树实现,保证元素有序(自然排序或 Comparator)
    • 插入/删除/查找 O(log n)
    • 不允许 null(需要比较)

4. CopyOnWriteArraySet

  • 底层数据结构:CopyOnWriteArrayList
  • 原理:
    • 内部用 CopyOnWriteArrayList 存储,通过 addIfAbsent() 去重
    • 写操作时复制整个底层数组,读操作无锁
    • 适用于读多写极少的并发场景
    • 迭代时使用快照,不会抛 ConcurrentModificationException

四、Queue / Deque 系列(队列)

1. PriorityQueue

  • 底层数据结构:Object[] 数组实现的二叉小顶堆
  • 原理:
    • 父节点 i,左子节点 2*i+1,右子节点 2*i+2
    • 插入/删除堆顶 O(log n)
    • 出队总是返回最小元素(自然排序或 Comparator)
    • 不是线程安全
    • 不允许 null

2. ArrayDeque

  • 底层数据结构:Object[] 循环数组
  • 原理:
    • 通过 head 和 tail 指针实现循环队列
    • 头尾插入/删除均 O(1)(均摊)
    • 扩容时分配新数组(2 倍),重新排列元素
    • 不允许 null(null 作为特殊返回值使用)
    • 比 LinkedList 做栈/队列更高效(数组连续内存,缓存友好)

3. LinkedList(同时实现 Deque)

  • 见上文 List 部分,可作为双向队列使用

4. ConcurrentLinkedQueue

  • 底层数据结构:单向链表 + CAS 无锁
  • 原理:
    • 使用 AtomicReference + CAS 操作实现无锁并发
    • tail 节点并非实时更新(惰性更新),减少 CAS 开销
    • 入队:CAS 修改尾节点 next 指针
    • 出队:CAS 修改 head 指针
    • 无界,线程安全,高性能

5. ConcurrentLinkedDeque

  • 底层数据结构:双向链表 + CAS 无锁
  • 原理:与 ConcurrentLinkedQueue 类似,但支持双向操作

6. ArrayBlockingQueue

  • 底层数据结构:Object[] 循环数组 + ReentrantLock
  • 原理:
    • 有界阻塞队列,创建时必须指定容量
    • 一把 ReentrantLock 控制 put 和 take,两个 Condition(notEmpty / notFull)实现阻塞等待
    • 公平/非公平模式可选(公平锁保证 FIFO 顺序)

7. LinkedBlockingQueue

  • 底层数据结构:单向链表 + 两把 ReentrantLock
  • 原理:
    • putLock + takeLock 分离,读写可并行
    • 默认容量 Integer.MAX_VALUE(无界风险)
    • notEmpty / notFull 两个 Condition 实现阻塞
    • 吞吐量通常高于 ArrayBlockingQueue

8. PriorityBlockingQueue

  • 底层数据结构:Object[] 二叉小顶堆 + ReentrantLock
  • 原理:
    • 与 PriorityQueue 相同的堆结构,加上线程安全
    • 无界,自动扩容
    • take() 时队列为空则阻塞等待
    • put() 永不阻塞(无界)

9. SynchronousQueue

  • 底层数据结构:无实际存储(公平模式用链表 TransferQueue,非公平模式用栈 TransferStack)
  • 原理:
    • 零容量,每个 put 必须等待一个 take,反之亦然
    • 直接在生产者和消费者之间传递元素
    • 公平模式(FIFO 队列)/ 非公平模式(LIFO 栈)
    • Executors.newCachedThreadPool() 使用此队列

10. DelayQueue

  • 底层数据结构:PriorityQueue + ReentrantLock
  • 原理:
    • 元素必须实现 Delayed 接口(getDelay() 返回剩余延迟时间)
    • 内部用 PriorityQueue 按延迟时间排序
    • take() 时如果队首元素未到期则阻塞
    • 适用于定时任务调度、缓存过期等场景

11. LinkedTransferQueue

  • 底层数据结构:单向链表 + CAS
  • 原理:
    • 实现 TransferQueue 接口,支持 transfer() 直接传递给消费者
    • 无锁实现,性能优于 LinkedBlockingQueue
    • tryTransfer() 如果有等待的消费者则立即传递,否则返回 false

五、Map 系列(键值对)

1. HashMap

  • 底层数据结构:数组 + 链表 + 红黑树(Java 8)
  • 原理:
    • 默认初始容量 16,负载因子 0.75,扩容 2 倍
    • 计算 key 的 hash:(h = key.hashCode()) ^ (h >>> 16) 扰动函数减少碰撞
    • 定位桶:index = (n - 1) & hash(等价于取模,要求容量为 2 的幂)
    • 链表长度 >= 8 且数组长度 >= 64 时,链表转红黑树
    • 红黑树节点 <= 6 时,退化回链表
    • 插入/查找/删除 平均 O(1),最坏 O(log n)
    • 允许一个 null key 和多个 null value
    • 非线程安全

2. LinkedHashMap

  • 底层数据结构:HashMap + 双向链表
  • 原理:
    • 继承 HashMap,在 Node 基础上增加 before / after 指针
    • 维护一条贯穿所有节点的双向链表
    • 支持插入顺序(默认)或访问顺序(accessOrder=true)
    • 访问顺序模式下,get() 会将节点移到链表尾部
    • 可重写 removeEldestEntry() 实现 LRU 缓存
    • 迭代顺序 = 链表顺序

3. TreeMap

  • 底层数据结构:红黑树
  • 原理:
    • key 按自然顺序或 Comparator 排序
    • 红黑树保证平衡,增删查 O(log n)
    • 支持范围查询:subMap()、headMap()、tailMap()
    • 不允许 null key

4. Hashtable

  • 底层数据结构:Entry[] 数组 + 链表
  • 原理:
    • 所有方法加 synchronized,线程安全但性能极差
    • 默认容量 11,扩容 2n+1 倍
    • 不允许 null key 和 null value
    • 已被淘汰,使用 ConcurrentHashMap 替代

5. IdentityHashMap

  • 底层数据结构:Object[] 数组(key 和 value 交替存储)
  • 原理:
    • key 的比较用 ==(引用相等)而非 equals()
    • hash 计算用 System.identityHashCode()
    • 适用于需要区分不同引用相同的对象的场景

6. WeakHashMap

  • 底层数据结构:Entry[] 数组 + 链表 + WeakReference
  • 原理:
    • key 是 WeakReference,当 key 对象只剩弱引用时,GC 会回收
    • GC 回收 key 后,Entry 会在下次操作时被清除
    • 适用于缓存场景,避免内存泄漏

7. EnumMap

  • 底层数据结构:Object[] 数组
  • 原理:
    • key 必须是同一枚举类的枚举值
    • 用枚举的 ordinal() 作为数组下标,O(1) 访问
    • 极致性能,内存紧凑
    • 不允许 null key

8. ConcurrentHashMap

  • 底层数据结构:数组 + 链表 + 红黑树(Java 8)
  • 原理:
    • 取消了 Java 7 的 Segment 分段锁,改用 CAS + synchronized 细粒度锁
    • 锁粒度:锁住链表/红黑树的头节点(桶级别)
    • put() 流程:
      1. 计算 hash 定位桶
      2. 桶为空 → CAS 写入
      3. 桶非空 → synchronized(头节点) 加锁后操作
      4. 链表长度 >= 8 → 转红黑树
    • size() 使用 baseCount + CounterCell[] 分散计数(类似 LongAdder)
    • 不允许 null key 和 null value
    • 线程安全,高并发性能优异

9. ConcurrentSkipListMap

  • 底层数据结构:跳表(SkipList)
  • 原理:
    • 多层有序链表,底层包含所有节点,上层是下层的"快速通道"
    • 查找从最高层开始,逐层向下,O(log n)
    • 插入时随机决定层数(概率 1/2 升一层)
    • 无锁并发:通过 CAS 操作实现
    • key 有序,支持并发范围查询
    • 适用于需要排序的并发 Map 场景

六、对比速查表

集合 底层结构 有序 线程安全 null 支持 时间复杂度
ArrayList 数组 插入序 否 允许 get O(1)
LinkedList 双向链表 插入序 否 允许 头尾 O(1)
HashSet HashMap 无序 否 允许一个null O(1)
LinkedHashSet LinkedHashMap 插入序 否 允许一个null O(1)
TreeSet TreeMap 红⿊树 排序序 否 不允许null O(log n)
PriorityQueue 小顶堆数组 优先级序 否 不允许null O(log n)
ArrayDeque 循环数组 FIFO/LIFO 否 不允许null O(1)
HashMap 数组+链表+红黑树 无序 否 允许一个null key O(1)
LinkedHashMap HashMap+双向链表 插入/访问序 否 允许一个null key O(1)
TreeMap 红黑树 排序序 否 不允许null key O(log n)
ConcurrentHashMap 数组+链表+红黑树 无序 是 不允许null O(1)
ConcurrentSkipListMap 跳表 排序序 是 不允许null O(log n)
ArrayBlockingQueue 循环数组+锁 FIFO 是 不允许null O(1)
LinkedBlockingQueue 链表+锁 FIFO 是 不允许null O(1)
SynchronousQueue 无存储 直传 是 不允许null -

七、选型建议

需要随机访问? → ArrayList
频繁头插/头删? → ArrayDeque / LinkedList
需要去重? → HashSet(无序)/ LinkedHashSet(有序)/ TreeSet(排序)
需要排序Map? → TreeMap / ConcurrentSkipListMap
需要LRU缓存? → LinkedHashMap (accessOrder=true)
需要并发? → ConcurrentHashMap / ConcurrentSkipListMap
需要阻塞队列? → ArrayBlockingQueue(有界) / LinkedBlockingQueue / SynchronousQueue
需要延迟队列? → DelayQueue
枚举做key? → EnumMap(性能最优)
posted @ 2026-05-12 16:56  webzd  阅读(31)  评论(0)    收藏  举报