在上一篇文章中,我們詳細介紹了 Collection 接口作為集合體系的根接口。本文將深入探討其核心子接口 List,解析其特有方法、核心實現類(ArrayList、LinkedList、Vector)的底層原理與最佳實踐,幫助你在實際開發中靈活選型、高效編碼。
List 接口繼承自 Collection,具有三大核心特徵:
equals() 比較為 true 即視為重複。Set 的關鍵。所有方法均圍繞「索引」展開,以下為高頻 API 分類速查:
// 在指定索引處插入單個元素,原索引及之後元素後移
void add(int index, E element);
// 批量插入集合,從指定索引開始
boolean addAll(int index, Collection<? extends E> c);
// 移除指定索引處元素,返回被移除的元素
E remove(int index);
// 替換指定索引處元素,返回舊元素
E set(int index, E element);
// 獲取指定索引元素
E get(int index);
// 正向查找首次出現索引,無則返回 -1
int indexOf(Object o);
// 反向查找最後出現索引
int lastIndexOf(Object o);
// 截取子列表 [fromIndex, toIndex) 左閉右開
List<E> subList(int fromIndex, int toIndex);
newCapacity = oldCapacity + (oldCapacity >> 1)),涉及 Arrays.copyOf 數組拷貝,頻繁擴容影響性能,建議預估數據量用 new ArrayList<>(initialCapacity)。get(i)、遍歷極快(O(1)),CPU 緩存友好。Collections.synchronizedList 或 CopyOnWriteArrayList。prev、next、item。Deque 接口)。get(i) 需遍歷(O(n)),記憶體佔用大(每個節點額外存兩個引用),不利於 CPU 緩存。synchronized。capacityIncrement 調整。| 場景 | 推薦實現類 | 理由 |
|---|---|---|
| 頻繁隨機訪問、遍歷、尾部增刪 | ArrayList | 數組連續內存,緩存命中率高,get/set O(1) |
| 頻繁頭部/中間增刪、作為隊列/棧 | LinkedList | 指針操作無需移動數據,實現 Deque 接口 |
| 多線程高併發讀寫 | CopyOnWriteArrayList | 寫時復制,讀無鎖,適合「讀多寫少」場景 |
| 多線程均衡讀寫 | Collections.synchronizedList(new ArrayList<>()) | 全量同步,簡單但吞吐一般 |
以下示例展示 List 常用操作,包含自定義對象存儲、索引操作、子列表截取等:
// 實體類
public class Course {
private String id;
private String name;
// 構造器、getter/setter、toString 省略
}
// 測試類
public class ListDemo {
public static void main(String[] args) {
List<Course> courses = new ArrayList<>();
// 1. 尾部新增
courses.add(new Course("1", "數據庫原理"));
courses.add(new Course("2", "Java 核心技術"));
// 2. 指定索引插入(頭部插入)
courses.add(0, new Course("0", "計算機導論")); // 現索引 0
// 3. 批量新增
Course[] newCourses = {
new Course("3", "高等數學"),
new Course("4", "大學英語")
};
courses.addAll(Arrays.asList(newCourses));
// 4. 指定位置批量插入
Course[] moreCourses = {
new Course("5", "高等語文"),
new Course("6", "數據處理")
};
courses.addAll(2, Arrays.asList(moreCourses)); // 插入到索引 2
// 5. 遍歷輸出
System.out.println("=== 所有課程 ===");
for (int i = 0; i < courses.size(); i++) {
System.out.printf("[%d] %s%n", i, courses.get(i));
}
// 6. 修改與刪除
Course old = courses.set(1, new Course("1", "數據庫系統工程師")); // 修改
System.out.println("修改前:" + old);
Course removed = courses.remove(3); // 刪除索引 3
System.out.println("刪除:" + removed);
// 7. 查找索引
int idx = courses.indexOf(new Course("2", "Java 核心技術")); // 需重寫 equals
System.out.println("Java 課程索引:" + idx);
// 8. 截取子列表(索引 1 到 4,不含 4)
List<Course> sub = courses.subList(1, 4);
System.out.println("子列表:" + sub);
}
}
new ArrayList<>(n) 避免多次擴容拷貝。Iterator.remove()、逆向遍歷或 Stream 流過濾。ConcurrentModificationException)。List<Course> list = new ArrayList<>(); 編譯期泛型,運行期擦除,取出時無需強轉。List.of()、Collections.unmodifiableList() 構建只讀列表,防止誤修改。List 接口賦予集合「有序、可重複、可索引」三大特性,ArrayList 與 LinkedList 分別代表「數組」與「鏈表」兩大經典數據結構在 Java 中的工程化實現。掌握其底層原理、擴容機制、時間複雜度差異,結合業務場景(查詢多選 ArrayList、增刪多選 LinkedList、併發選 CopyOnWriteArrayList),才能寫出高性能、穩健的 Java 代碼。下一篇我們將深入 Set 接口及其 HashSet、LinkedHashSet、TreeSet 實現,敬請期待!