一、List 接口概述
1. 基本定義
- 繼承關系:
List
?是 Java 集合框架(Collection Framework)中的一個有序隊列接口,直接繼承自?Collection
?接口。 - 核心特性:
- 有序性:元素按插入順序存儲,可通過索引(Index)訪問元素。
- 可重復性:允許存儲重復元素。
- 動態擴容:底層實現類(如?
ArrayList
、LinkedList
)支持動態調整容量。
2. 與其他接口的區別
接口 | 有序性 | 重復性 | 數據結構 | 典型實現類 |
---|---|---|---|---|
List | 是 | 是 | 線性表 | ArrayList 、LinkedList |
Set | 否 | 否 | 集合(哈希表等) | HashSet 、TreeSet |
Queue | 是 | 是 | 隊列(FIFO) | LinkedList 、PriorityQueue |
二、List 接口核心方法
1. 元素操作方法
(1)添加元素
boolean add(E e)
:向列表末尾添加元素,成功返回?true
。
List<String> list = new ArrayList<>();
list.add("Apple"); // 添加到末尾
void add(int index, E element)
:在指定索引處插入元素,后續元素后移。
list.add(1, "Banana"); // 在索引1處插入元素
(2)刪除元素
E remove(int index)
:移除指定索引處的元素,返回被刪除元素。
String removed = list.remove(0); // 移除索引0的元素
boolean remove(Object o)
:移除列表中第一個匹配的元素(通過?equals
?方法判斷)。
list.remove("Apple"); // 移除值為"Apple"的元素
(3)修改元素
E set(int index, E element)
:用指定元素替換指定索引處的元素,返回舊元素。
String oldValue = list.set(0, "Grape"); // 將索引0的元素改為"Grape"
(4)查詢元素
E get(int index)
:返回指定索引處的元素。
String first = list.get(0); // 獲取索引0的元素
int indexOf(Object o)
:返回元素首次出現的索引,不存在則返回?-1
。
int pos = list.indexOf("Banana"); // 查詢"Banana"的位置
int lastIndexOf(Object o)
:返回元素最后一次出現的索引,不存在則返回?-1
。
2. 集合操作方法
boolean contains(Object o)
:判斷列表是否包含指定元素(基于?equals
)。boolean.addAll(Collection<? extends E> c)
:將其他集合的所有元素添加到列表末尾。void clear()
:移除列表中的所有元素。boolean isEmpty()
:判斷列表是否為空。int size()
:返回列表中的元素個數。
3. 迭代與視圖方法
- 迭代器(Iterator):
Iterator<String> it = list.iterator();
while (it.hasNext()) {String element = it.next();// 處理元素
}
列表迭代器(ListIterator):支持雙向遍歷和元素修改:
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {String element = lit.next();lit.set(element + "_modified"); // 修改元素
}
- 子列表(SubList):返回列表中指定范圍的視圖(
List.subList(int fromIndex, int toIndex)
):
List<String> sub = list.subList(0, 2); // 包含索引0,不包含索引2
三、List 接口的實現類
1. ArrayList
(1)特點
- 底層結構:動態數組(
Object[]
)。 - 優缺點:
- ? 隨機訪問(
get(int)
)速度快(時間復雜度 O (1))。 - ? 插入 / 刪除元素時需移動后續元素,效率較低(時間復雜度 O (n))。
- ? 隨機訪問(
- 適用場景:頻繁查詢、較少增刪的場景(如數據展示、日志記錄)。
(2)擴容機制
- 初始容量默認值為?
10
(JDK 1.8)。 - 當元素數量超過容量時,新容量為?原容量的 1.5 倍(通過?
Arrays.copyOf
?復制數組)。
2. LinkedList
(1)特點
- 底層結構:雙向鏈表(每個節點包含?
prev
、next
?指針)。 - 優缺點:
- ? 插入 / 刪除元素時只需修改指針,效率高(時間復雜度 O (1),若已知節點位置)。
- ? 隨機訪問需遍歷鏈表,效率低(時間復雜度 O (n))。
- 適用場景:頻繁增刪的場景(如隊列、棧、緩存)。
(2)特殊方法
- 可作為隊列(Queue)使用:
LinkedList<String> queue = new LinkedList<>();
queue.offer("A"); // 入隊(添加到末尾)
String first = queue.poll(); // 出隊(移除并返回頭部元素)
可作為棧(Stack)使用:
queue.push("B"); // 入棧(添加到頭部)
String last = queue.pop(); // 出棧(移除并返回頭部元素)
3. Vector(線程安全)
(1)特點
- 底層結構:動態數組,與?
ArrayList
?類似。 - 線程安全:方法通過?
synchronized
?修飾(如?add()
、get()
),但性能較低。 - 適用場景:多線程環境下需要線程安全的場景(較冷門,推薦使用?
Collections.synchronizedList()
?替代)。
4. 實現類對比表
實現類 | 底層結構 | 線程安全 | 隨機訪問效率 | 增刪效率(中間位置) | 默認初始容量 |
---|---|---|---|---|---|
ArrayList | 動態數組 | 否 | 高(O (1)) | 低(O (n)) | 10 |
LinkedList | 雙向鏈表 | 否 | 低(O (n)) | 高(O (1)) | - |
Vector | 動態數組 | 是 | 高(O (1)) | 低(O (n)) | 10 |
四、List 接口的常用操作場景
1. 遍歷列表的 4 種方式
(1)普通 for 循環(索引遍歷)
for (int i = 0; i < list.size(); i++) {String element = list.get(i);
}
適用場景:需要通過索引操作元素(如修改、刪除)。
(2)增強 for 循環(foreach)
for (String element : list) {// 只讀操作元素
}
注意:遍歷時若修改列表(如?list.remove()
),會拋出?ConcurrentModificationException
(fail-fast 機制)。
(3)Iterator 迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {String element = it.next();if (element.equals("Apple")) {it.remove(); // 安全刪除元素的方式}
}
優勢:支持遍歷過程中安全刪除元素(通過?Iterator.remove()
)。
(4)Java 8 Stream 流式遍歷
list.stream().forEach(element -> {System.out.println(element);
});
適用場景:結合 Lambda 表達式實現復雜邏輯(如過濾、映射)。
2. 列表排序與搜索
(1)排序(Collections.sort()
)
List<Integer> nums = Arrays.asList(3, 1, 4, 2);
Collections.sort(nums); // 升序排列(默認自然排序)
// 自定義排序(降序)
Collections.sort(nums, (a, b) -> b - a);
(2)二分查找(Collections.binarySearch()
)
Collections.sort(nums); // 需先排序
int index = Collections.binarySearch(nums, 3); // 返回元素3的索引
3. 線程安全處理
- 場景:多線程環境下操作?
List
?時,需保證線程安全。 - 解決方案:
- 使用?
Vector
(性能較低)。 - 通過?
Collections.synchronizedList()
?包裝普通?List
:
- 使用?
List<String> safeList = Collections.synchronizedList(new ArrayList<>());
使用并發包?java.util.concurrent
?中的?CopyOnWriteArrayList
(適用于讀多寫少場景):
List<String> concurrentList = new CopyOnWriteArrayList<>();
五、常見問題與最佳實踐
1. ArrayList vs LinkedList 如何選擇?
- 優先選 ArrayList:需要頻繁隨機訪問(如查詢),或數據量已知、增刪操作少。
- 優先選 LinkedList:需要頻繁在頭部 / 中間插入 / 刪除元素,或數據量不確定、需高效動態調整。
2. 列表擴容的性能影響
ArrayList
?擴容時會創建新數組并復制舊元素,若初始容量預估不足,多次擴容會導致性能下降。- 最佳實踐:通過構造方法指定初始容量:
List<String> list = new ArrayList<>(100); // 初始容量設為100,減少擴容次數
3. 避免內存泄漏
- 若存儲大量對象,需及時調用?
clear()
?或置為?null
,幫助垃圾回收器回收內存。 - 強制類型轉換風險:非泛型?
List
?會存儲?Object
?類型,取出時需強制類型轉換,可能引發?ClassCastException
。 - 最佳實踐:使用泛型限定元素類型:
List<String> list = new ArrayList<>(); // 限定只能存儲String類型
六、總結
特性 | List 接口特點 |
---|---|
核心優勢 | 有序性、可重復性、索引訪問,適用于需要按順序操作的數據場景。 |
實現類選擇 | - 高頻查詢:ArrayList - 高頻增刪: LinkedList - 線程安全: CopyOnWriteArrayList |
常用操作 | 添加 / 刪除元素、遍歷、排序、子列表操作、線程安全處理。 |
通過掌握?List
?接口的核心方法與實現類特性,可在開發中高效處理線性數據集合,提升代碼的健壯性與性能。