首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java List 介面完整指南:ArrayList、LinkedList、Vector 核心差異與實戰選型

     編輯:Java 相關知識

前言

List 是 Java 集合框架中有序、可重複的集合介面。三大主流實作——ArrayList、LinkedList、Vector——在底層資料結構、效能特性、執行緒安全性上有本質差異。本文系統對比三者,提供選型決策樹與最佳實務。

核心架構對比

特性ArrayListLinkedListVector
底層結構動態陣列雙向鏈結串列動態陣列
執行緒安全否否是 (方法同步)
擴容機制1.5 倍無 (節點動態分配)2 倍
隨機存取 get(index)O(1) ⭐O(n) - 需遍歷O(1)
頭尾增刪O(n) - 需搬移O(1) ⭐O(n)
中間增刪O(n) - 需搬移O(n) - 需遍歷到位置O(n)
記憶體開銷低 (連續記憶體)高 (每節點 3 個參考)低
實作介面List, RandomAccess, Cloneable, SerializableList, Deque, Cloneable, SerializableList, RandomAccess, Cloneable, Serializable

List 介面獨有方法(索引相關)


// 位置操作
void add(int index, E element)
boolean addAll(int index, Collection c)
E get(int index)
E set(int index, E element)
E remove(int index)
int indexOf(Object o)
int lastIndexOf(Object o)
List subList(int fromIndex, int toIndex) // 視圖,非複製
ListIterator listIterator()
ListIterator listIterator(int index)

ArrayList 實戰範例


List list = new ArrayList<>();
list.add("Java");      // [Java]
list.add("Python");    // [Java, Python]
list.add(1, "Go");     // [Java, Go, Python] - 指定索引插入

System.out.println(list.get(1)); // Go
list.set(1, "Rust");             // [Java, Rust, Python] - 替換
list.remove(0);                  // [Rust, Python] - 移除索引 0

// 批次操作
List more = List.of("C++", "JS");
list.addAll(0, more);            // [C++, JS, Rust, Python]

// 子列表視圖(修改視圖會影響原列表)
List sub = list.subList(1, 3); // [JS, Rust]
sub.set(0, "TypeScript");            // 原列表也變: [C++, TypeScript, Rust, Python]

LinkedList 實戰範例(Deque 雙端操作)


Deque deque = new LinkedList<>();
deque.addFirst("Head");   // 等同 push
deque.addLast("Tail");    // 等同 add/offer
deque.offerFirst("NewHead");
deque.offerLast("NewTail");

System.out.println(deque.peekFirst()); // 查看頭不移除
System.out.println(deque.pollFirst()); // 取出並移除頭
System.out.println(deque.pollLast());  // 取出並移除尾

// JDK 1.6+ 新增方法(無例外版本)
deque.offerFirst(x); // 等同 addFirst 但不拋例外
deque.peekFirst();   // 等同 getFirst 但空回傳 null
deque.pollFirst();   // 等同 removeFirst 但空回傳 null

ListIterator:雙向游標與修改

ListIterator 繼承 Iterator,新增反向遍歷、索引查詢、元素修改/新增:


List list = new ArrayList<>(List.of("A", "B", "C", "D"));
ListIterator it = list.listIterator();

while (it.hasNext()) {
    String val = it.next();
    if ("B".equals(val)) {
        it.set("B-Modified");  // 修改剛讀取的元素
        it.add("Inserted");    // 在游標前插入
    }
}
// 結果: [A, B-Modified, Inserted, C, D]

// 反向遍歷
while (it.hasPrevious()) {
    System.out.println(it.previousIndex() + ": " + it.previous());
}

Vector 與同步包裝

Vector 所有方法 synchronized,效能差,已被淘汰。現代替代方案:


// 1. Collections.synchronizedList (鎖住整個列表)
List syncList = Collections.synchronizedList(new ArrayList<>());
// 迭代時必須手動同步:
synchronized (syncList) {
    for (String s : syncList) { ... }
}

// 2. CopyOnWriteArrayList (讀多寫少、快照迭代)
List cowList = new CopyOnWriteArrayList<>();
// 迭代不需同步,寫入時複製底層陣列

// 3. 並發佇列 (生產者-消費者)
BlockingQueue queue = new LinkedBlockingQueue<>();

選型決策樹


需要執行緒安全?
├── 是 → 讀多寫少、需快照迭代? → CopyOnWriteArrayList
│         └── 否 → 生產者消費者模式? → BlockingQueue (LinkedBlockingQueue)
│                  └── 否 → 一般同步需求 → Collections.synchronizedList(ArrayList)
└── 否 → 頻繁頭尾增刪、雙端操作? → LinkedList (或 ArrayDeque)
         └── 否 → 頻繁隨機存取、遍歷、末端新增? → ArrayList (預設首選)
                  └── 否 → 中間頻繁增刪? → 考慮 LinkedList 或重新設計資料結構

效能實測參考 (JMH, 100萬元素)

操作ArrayListLinkedListVector
序列新增 add(e)~5 ms~15 ms~45 ms
隨機存取 get(i)~0.001 ms~120 ms~0.001 ms
頭端插入 add(0,e)~180 ms~0.002 ms~350 ms
中間插入 add(n/2,e)~90 ms~60 ms~170 ms
迭代遍歷~3 ms~18 ms~5 ms

常見陷阱

  • subList 回傳視圖,結構性修改原列表會導致視圖失效拋 ConcurrentModificationException
  • ListIterator 與 Iterator 不可混用於同一列表修改
  • Arrays.asList() 回傳固定大小列表,不可增刪,僅可 set
  • 多執行緒環境直接用 ArrayList 會導致資料損毀或無限循環

總結

90% 場景首選 ArrayList:快取友善、記憶體效率高、隨機存取 O(1)。LinkedList 專用於頻繁頭尾操作或實作 Deque。Vector 已淘汰,同步需求改用 Collections.synchronizedList、CopyOnWriteArrayList 或並發佇列。理解底層資料結構與效能特性,才能寫出高效、正確的集合操作代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved