黑洞来咯
89.71MB · 2026-02-15
在Java集合框架中,Collection和Map是两大核心接口,它们并列存在而非继承关系。许多开发者混淆两者,导致在实际开发中选择错误的集合类型。本文将从JDK 1.8+源码底层深度剖析Collection和Map接口的所有实现类,揭示其算法逻辑,并总结最佳实践与避坑指南。所有内容均基于官方源码,确保技术准确性。
Collection和Map是Java集合框架的两个独立顶层接口,它们没有继承关系,而是并列存在。以下是完整的继承关系图:
Collection:
ArrayList:基于数组的动态集合核心结构:transient Object[] elementData;(默认容量10)
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private transient Object[] elementData;
private int size;
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
算法逻辑:
newCapacity = oldCapacity * 1.5add(E e):均摊 O(1)(扩容时O(n))get(int index):O(1)(数组随机访问)remove(int index):O(n)(需移动后续元素)LinkedList:基于双向链表的集合核心结构:private static class Node<E> { E item; Node<E> next; Node<E> prev; }
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
public boolean add(E e) {
linkLast(e);
return true;
}
private void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
}
}
算法逻辑:
prev 和 next 指针add(E e):O(1)(尾部添加)get(int index):O(n)(需遍历)remove(int index):O(n)(需定位节点)HashSet:基于 HashMap 的无序集合核心结构:private transient HashMap<E,Object> map;(key 为集合元素,value 为 PRESENT)
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT) == null; // 实际调用HashMap的put
}
}
算法逻辑:
HashMap 的链表+红黑树(JDK 8+)add(E e):均摊 O(1)contains(E e):均摊 O(1)hashCode() 和 equals()LinkedHashSet:基于 LinkedHashMap 的有序集合核心结构:private transient LinkedHashMap<E,Object> map;(继承自 HashSet)
public class LinkedHashSet<E> extends HashSet<E> {
public LinkedHashSet() {
super(16, 0.75f, true); // accessOrder=true
}
}
算法逻辑:
LinkedHashMap 的 accessOrder(访问顺序)或 insertOrder(插入顺序)HashSet 相同(均摊 O(1))TreeSet:基于 TreeMap 的有序集合核心结构:private transient TreeMap<E,Object> m;(key 为集合元素,value 为 PRESENT)
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable {
private transient NavigableMap<E,Object> m;
public TreeSet() {
m = new TreeMap<>();
}
public boolean add(E e) {
return m.put(e, PRESENT) == null; // 实际调用TreeMap的put
}
}
算法逻辑:
Comparable 或提供 Comparatoradd(E e):O(log n)contains(E e):O(log n)headSet(), subSet())PriorityQueue:基于堆的优先队列核心结构:transient Object[] queue;(数组实现的二叉堆)
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {
private transient Object[] queue;
private int size;
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e); // 堆调整(上浮)
return true;
}
private void siftUp(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E)e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
}
算法逻辑:
comparator 可自定义)offer(E e):O(log n)poll():O(log n)ArrayDeque:基于循环数组的双端队列核心结构:transient Object[] elements;(数组+头尾指针)
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, java.io.Serializable {
transient Object[] elements;
private int head;
private int tail;
public boolean add(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
if (tail == elements.length - 1)
tail = 0;
else
tail++;
if (head == tail)
doubleCapacity();
return true;
}
}
算法逻辑:
head 和 tail 指针维护队列newCapacity = oldCapacity * 2)addFirst(E e):O(1)addLast(E e):O(1)Vector 和 Stack:过时实现(避免使用!)Vector:线程安全(synchronized 方法),扩容为2倍(oldCapacity * 2)Stack:继承 Vector,过时(建议用 ArrayDeque 代替)HashMap:基于哈希表的无序映射核心结构:transient Node<K,V>[] table;(数组+链表/红黑树)
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
// ...
}
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // 8
treeifyBin(tab, hash);
break;
}
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
算法逻辑:
hash = key.hashCode() ^ (key.hashCode() >>> 16)newCapacity = oldCapacity * 2)put(K key, V value):均摊 O(1)(链表)/ O(log n)(红黑树)get(K key):均摊 O(1)hashCode() 和 equals()LinkedHashMap:基于 HashMap 的有序映射核心结构:transient Entry<K,V> head;(双向链表维护顺序)
public class LinkedHashMap<K,V> extends HashMap<K,V> {
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false; // 插入顺序
}
@Override
void afterNodeAccess(Node<K,V> e) {
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b != null)
b.after = a;
else
head = a;
if (a != null)
a.before = b;
else
last = b;
if (last != null)
last.after = p;
p.before = last;
p.after = null;
tail = p;
++modCount;
}
}
}
算法逻辑:
before/after 指针维护插入顺序(accessOrder=false)或访问顺序(accessOrder=true)HashMap 相同(均摊 O(1))accessOrder=true)TreeMap:基于红黑树的有序映射核心结构:private transient Entry<K,V> root;(红黑树节点)
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable {
static final class Entry<K,V> {
K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK;
// ...
}
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
do {
parent = t;
cmp = compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
算法逻辑:
O(log n) 操作Comparable 或提供 Comparatorput(K key, V value):O(log n)get(K key):O(log n)Hashtable:线程安全的哈希映射(已过时)核心结构:transient Entry<K,V>[] table;(与 HashMap 类似,但加锁)
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable {
private transient Entry<K,V>[] table;
public synchronized V put(K key, V value) {
if (value == null)
throw new NullPointerException();
Entry<K,V> entry = getEntry(key);
if (entry != null) {
V oldValue = entry.value;
entry.value = value;
return oldValue;
} else {
addEntry(hash(key), key, value, table.length);
return null;
}
}
private void addEntry(int hash, K key, V value, int index) {
Entry<K,V> e = table[index];
table[index] = new Entry<>(hash, key, value, e);
if (++count >= threshold)
resize(2 * table.length);
}
}
算法逻辑:
synchronized 修饰(锁粒度粗,性能差)newCapacity = oldCapacity * 2)HashMap 相同(O(1)),但性能低10倍+ConcurrentHashMap| 特性 | Collection 接口 | Map 接口 |
|---|---|---|
| 数据结构 | 单元素集合(List/Set/Queue) | 键值对映射(Key-Value) |
| 核心方法 | add(E e), remove(E e), size() | put(K key, V value), get(K key) |
| 是否允许重复 | List:允许;Set:不允许 | Key:不允许;Value:允许 |
| 底层实现 | 数组/链表/红黑树 | 哈希表/红黑树 |
| 典型场景 | 存储列表、集合、队列 | 存储配置、缓存、关联数据 |
| 线程安全 | Collections.synchronizedList() | ConcurrentHashMap(非 Hashtable) |
| 遍历方式 | iterator(), forEach() | keySet(), entrySet(), values() |
| 关键设计原则 | 元素操作 | 键值对操作 |
| 操作场景 | 推荐集合 | 原因 |
|---|---|---|
| 单元素集合 | ArrayList | 随机访问 O(1),缓存友好 |
| 频繁头尾插入/删除 | LinkedList | O(1) 头尾操作 |
| 自动去重 + 快速查找 | HashSet | 均摊 O(1) 查找 |
| 保留插入顺序的去重 | LinkedHashSet | 插入顺序,性能略低于 HashSet |
| 排序 + 范围查询 | TreeSet | O(log n) 操作,自动排序 |
| 优先级任务调度 | PriorityQueue | O(log n) 插入/删除 |
| 高性能双端队列 | ArrayDeque | 比 LinkedList 更快(无指针开销) |
| 键值对快速查找 | HashMap | 均摊 O(1) 查找,无序 |
| 保留插入顺序的键值对 | LinkedHashMap | LRU缓存实现(accessOrder=true) |
| 排序键值对 | TreeMap | O(log n) 操作,自动按键排序 |
| 线程安全的键值对 | ConcurrentHashMap | 高性能并发(Hashtable 已过时) |
Vector 用于多线程
Vector 的 synchronized 锁粒度粗,性能极低。Map<String, String> map = new ConcurrentHashMap<>(); 或 ConcurrentLinkedQueue循环中直接 remove()
for (E e : list) list.remove(e) → ConcurrentModificationException。Iterator 遍历:
Iterator<E> it = list.iterator();
while (it.hasNext()) {
if (condition) it.remove();
}
HashMap 键未重写 hashCode()/equals()
new Person("A") 和 new Person("A") 被视为不同键。hashCode() 和 equals()(推荐Lombok @EqualsAndHashCode)。误用 Hashtable 代替 ConcurrentHashMap
Hashtable 的 synchronized 导致性能低下。Map<String, String> map = new ConcurrentHashMap<>();迭代时修改 Map
for (Map.Entry<String, String> e : map.entrySet()) map.remove(e.getKey());Iterator 或 removeIf():
map.entrySet().removeIf(e -> e.getKey().equals("target"));
TreeMap 未实现 Comparable
TreeMap<CustomObject, String> → ClassCastException。Comparator 或让类实现 Comparable。忽略 HashMap 的扩容
new HashMap<>(1024)。Collection vs Map:
Collection 处理元素(如 List),Map 处理键值对(如 HashMap)。选择集合的黄金法则:
Collection 实现类。Map 实现类。ConcurrentHashMap 代替 Hashtable。性能与正确性:
HashMap/HashSet:必须重写 hashCode() 和 equals()。TreeMap/TreeSet:必须保证键的排序(Comparable 或 Comparator)。ConcurrentHashMap:避免在迭代时修改(用 computeIfPresent 等方法)。参考资料