AbstractCollection 是集合框架的骨架實現類,提供了 Collection 接口中除 iterator() 和 size() 之外的通用默認實現。理解其源碼,能洞悉:
toArray() 的動態擴容)Collection 定義了集合的基本語義:
size()、isEmpty()、contains()、containsAll()add()、remove()、addAll()、removeAll()、retainAll()、clear()toArray()、toArray(T[])iterator()、forEach() (Java 8+)equals()、hashCode()public boolean isEmpty() {
return size() == 0; // 委派給 size(),子類必須實現
}
public boolean contains(Object o) {
Iterator<E> it = iterator(); // 統一通過迭代器遍歷
if (o == null) {
while (it.hasNext())
if (it.next() == null) return true; // null 專用比較
} else {
while (it.hasNext())
if (o.equals(it.next())) return true; // 非 null 用 equals
}
return false;
}
設計亮點:null 單獨判斷避免 NullPointerException;完全依賴 iterator() 實現算法與數據結構解耦。
將集合轉為數組看似簡單,實則暗藏併發擴容、類型安全、性能優化三大挑戰。
public Object[] toArray() {
Object[] r = new Object[size()]; // 1. 預分配數組
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (!it.hasNext()) // 2. 併發場景:元素變少
return Arrays.copyOf(r, i); // 截斷返回
r[i] = it.next();
}
// 3. 併發場景:元素變多
return it.hasNext() ? finishToArray(r, it) : r;
}
public <T> T[] toArray(T[] a) {
int size = size();
// 1. 判斷傳入數組是否足夠大
T[] r = a.length >= size ? a : (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (!it.hasNext()) { // 元素變少
if (a == r) r[i] = null; // 填充 null 終結
else if (a.length < i) return Arrays.copyOf(r, i); // 截斷
else { System.arraycopy(r, 0, a, 0, i); if (a.length > i) a[i] = null; return a; }
}
r[i] = (T) it.next();
}
// 元素變多:動態擴容
return it.hasNext() ? finishToArray(r, it) : r;
}
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) { // 擴容觸發點
int newCap = cap + (cap >> 1) + 1; // 1.5倍 + 1 增長策略
if (newCap - MAX_ARRAY_SIZE > 0) newCap = hugeCapacity(cap + 1); // 溢出保護
r = Arrays.copyOf(r, newCap); // 複製到新數組
}
r[i++] = (T) it.next();
}
return (i == r.length) ? r : Arrays.copyOf(r, i); // 修剪多餘容量
}
關鍵設計決策解讀:
| 設計點 | 原理 | 意義 |
|---|---|---|
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 | 部分 JVM 數組頭部佔用 8 字節 | 防止申請過大數組導致 OOM: Requested array size exceeds VM limit |
| 併發下 size() 與 hasNext() 不一致 | 弱一致性策略:動態擴容/截斷適應 | 不拋出異常,盡力返回當前快照;ArrayList 選擇 fail-fast 直接拋異常 |
| 擴容因子 1.5 (cap + cap/2 + 1) | 平衡內存浪費與擴容頻次 | 優於 2 倍(浪費大)和 1.125 倍(頻繁擴容) |
| Arrays.copyOf vs System.arraycopy | copyOf 內部調用 arraycopy 並創建新數組 | copyOf 更安全易用;arraycopy 底層原語,性能極致場景直用 |
// 默認拋出異常,強制子類實現(如 ArrayList 重寫為真實添加)
public boolean add(E e) { throw new UnsupportedOperationException(); }
// 移除單個元素:通過迭代器遍歷匹配並調用 it.remove()
public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o == null) { while (it.hasNext()) if (it.next() == null) { it.remove(); return true; } }
else { while (it.hasNext()) if (o.equals(it.next())) { it.remove(); return true; } }
return false;
}
// 批量操作:全部委派迭代器,體現「算法在父類、數據在子類」
public boolean containsAll(Collection<?> c) { for (Object e : c) if (!contains(e)) return false; return true; }
public boolean addAll(Collection<? extends E> c) { boolean mod=false; for(E e:c) if(add(e)) mod=true; return mod; }
public boolean removeAll(Collection<?> c) { boolean mod=false; Iterator<?> it=iterator(); while(it.hasNext()) if(c.contains(it.next())){ it.remove(); mod=true; } return mod; }
public boolean retainAll(Collection<?> c) { boolean mod=false; Iterator<E> it=iterator(); while(it.hasNext()) if(!c.contains(it.next())){ it.remove(); mod=true; } return mod; }
public void clear() { Iterator<E> it=iterator(); while(it.hasNext()){ it.next(); it.remove(); } }
核心洞察:所有批量操作完全依賴迭代器,實現了算法邏輯與具體存儲結構完全分離。子類只需實現 iterator() 返回合適的 Iterator 實例,即可免費獲得所有通用操作。
public String toString() {
Iterator<E> it = iterator();
if (!it.hasNext()) return "[]";
StringBuilder sb = new StringBuilder('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e); // 防止自我引用無限遞歸
if (!it.hasNext()) return sb.append(']').toString();
sb.append(',').append(' ');
}
}
| 方法 | ArrayList | HashSet | LinkedList | 重寫原因 |
|---|---|---|---|---|
| size() | O(1) 字段 | O(1) 字段 | O(1) 字段 | 父類抽象,必須實現 |
| iterator() | Itr 內部類 | KeyIterator | ListItr | 父類抽象,必須實現 |
| 重寫:系統數組拷貝+fail-fast | 繼承父類 | 繼承父類 | ArrayList 底層就是數組,可極致優化;fail-fast 保證併發一致性 | |
| add/remove | 重寫:數組擴容/移位 | 重寫:HashMap 操作 | 重寫:鏈表指針調整 | 父類默認拋異常/通用算法效率低 |
| contains | 重寫:indexOf 線性查找 | 重寫:HashMap O(1) | 繼承父類 | HashSet 利用哈希優化;LinkedList 無索引只能遍歷 |