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

Java ArrayList 與陣列互轉完全指南:toArray、asList 與避坑指南

     編輯:Java 相關知識

前言

List 與陣列互轉是 Java 開發高頻操作。API 看似簡單,但 toArray() 重載陷阱、Arrays.asList() 固定長度限制、基本類型無法直接轉換等細節極易踩坑。本文系統梳理互轉姿勢、記憶體語義、最佳實踐與避坑清單。

List → 陣列:toArray() 兩種形態

1. 無參 toArray() → Object[](較少用)


List list = Arrays.asList("A", "B", "C");
Object[] objArr = list.toArray(); // 類型擦除,只能得到 Object[]
// String[] strArr = (String[]) objArr; // ❌ ClassCastException!

缺點: 運行時類型為 Object[],無法安全轉型為具體類型陣列。

2. 有參 toArray(T[] a) → 精確類型陣列(推薦)


List list = Arrays.asList("A", "B", "C");

// 寫法一:傳入「零長度陣列」(JDK 6+ 推薦,JIT 會優化分配精確大小)
String[] arr1 = list.toArray(new String[0]); // ✅ 最簡潔、效能佳

// 寫法二:傳入「預估大小陣列」(舊版 JDK 推薦,避免反射分配)
String[] arr2 = list.toArray(new String[list.size()]); // ✅ 也可

// 寫法三:大小不足時自動擴容(語義同上)
String[] arr3 = list.toArray(new String[10]); // 實際只用前 3 位,第 4 位置 null

核心規則(Javadoc)

  • 若傳入陣列長度 ≥ list.size():直接填充該陣列,剩餘位置置 null,返回同一陣列引用。
  • 若傳入陣列長度 < list.size():反射分配新陣列(Array.newInstance),返回新陣列引用。
  • JDK 6+ 建議傳 new T[0]:逃逸分析 + 標量替換可消除分配開銷,比預估大小更快。

陣列 → List:Arrays.asList() 與陷阱

1. Arrays.asList() 返回固定長度 List


String[] arr = {"A", "B", "C"};
List list = Arrays.asList(arr); // 返回 Arrays$ArrayList(非 java.util.ArrayList)

// 特性:
list.get(0);        // ✅
list.set(0, "X");   // ✅ 修改元素 → 原陣列同步變化
list.add("D");      // ❌ UnsupportedOperationException(長度固定)
list.remove(0);     // ❌ UnsupportedOperationException

2. 陣列與 List 共享記憶體


String[] arr = {"A", "B"};
List list = Arrays.asList(arr);
list.set(0, "Z");
System.out.println(arr[0]); // "Z" —— 修改 List 影響原陣列
arr[1] = "Y";
System.out.println(list.get(1)); // "Y" —— 修改陣列影響 List

3. 基本類型陣列無法直接轉 List


int[] primitiveArr = {1, 2, 3};
// List list = Arrays.asList(primitiveArr); // ❌ 編譯錯誤:泛型不支持基本類型
// Arrays.asList(primitiveArr) 返回 List,長度為 1,元素是原陣列引用

// 正確姿勢:流式轉換(JDK 8+)
List list = Arrays.stream(primitiveArr).boxed().collect(Collectors.toList());
// 或第三方庫
// List list = IntStream.of(primitiveArr).boxed().collect(toList());

獲取可變 ArrayList:三種姿勢


// 1. new ArrayList<>(Arrays.asList(...)) —— 經典,複製一份
List mutable1 = new ArrayList<>(Arrays.asList("A", "B"));

// 2. Collections.addAll() —— 效能最佳(避免中間 List 對象)
List mutable2 = new ArrayList<>();
Collections.addAll(mutable2, "A", "B", "C"); // 或 Collections.addAll(mutable2, arr);

// 3. Stream API(JDK 8+)—— 函數式風格
List mutable3 = Stream.of("A", "B", "C").collect(Collectors.toList());
// 並行大數據
List mutable4 = Arrays.stream(arr).parallel().collect(Collectors.toList());

多維陣列與泛型陷阱


// 二維陣列轉 List
String[][] matrix = {{"A","B"}, {"C","D"}};
List rowList = Arrays.asList(matrix); // List,每行是陣列引用
// rowList.add(new String[]{"E"}); // ❌ 固定長度

// 深度轉換需手動
List> deepList = Arrays.stream(matrix)
    .map(row -> new ArrayList<>(Arrays.asList(row)))
    .collect(Collectors.toList());

效能對比(JMH,100萬元素)


Benchmark                          Mode  Cnt    Score   Error  Units
toArray_newZero                    thrpt   5  125.3 ±  2.1  ops/ms  (new String[0])
toArray_newSize                    thrpt   5  118.7 ±  1.8  ops/ms  (new String[size])
stream_boxed_collect               thrpt   5   45.2 ±  0.9  ops/ms  (基本類型轉換)
Collections_addAll                 thrpt   5  210.5 ±  3.4  ops/ms  (陣列→可變List最快)

避坑檢查清單

陷阱錯誤代碼正確代碼原因
toArray() 強轉(String[]) list.toArray()list.toArray(new String[0])運行時類型 Object[]
asList 添加/刪除Arrays.asList(arr).add("X")new ArrayList<>(Arrays.asList(arr))返回固定長度視圖
基本類型陣列 asListArrays.asList(intArr)IntStream.of(intArr).boxed().collect(toList())泛型擦除,推導為 List
修改視圖影響原陣列list.set(0,"X") 後驚訝 arr 變了new ArrayList<>(Arrays.asList(arr)) 斷開共享asList 無拷貝,共享底層陣列
傳入過大陣列污染 nulllist.toArray(new String[100])list.toArray(new String[0])剩餘位置置 null,可能誤判長度

總結

  1. List → 陣列: list.toArray(new T[0]) 一把梭(簡潔、高效、類型安全)。
  2. 陣列 → 可變 List: new ArrayList<>(Arrays.asList(arr)) 或 Collections.addAll(new ArrayList<>(), arr)。
  3. 基本類型陣列: 必須用 Stream boxed() 或第三方庫轉包裝類型 List。
  4. 記憶體語義: asList 視圖共享底層陣列,new ArrayList 獨立拷貝。
  5. 只讀場景: 直接用 Arrays.asList(arr) 或 List.of(...) (JDK 9+),零拷貝、真不可變。

掌握這些,List 與陣列互轉不再有坑!

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