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

Arrays.asList() 核心源碼解析:為什麼返回的 List 不支持 add/remove?

     編輯:Java 相關知識

現象複現

List<String> list = Arrays.asList("A", "B", "C");
list.add("D"); // 拋出 UnsupportedOperationException

源碼追蹤(JDK 17)

1. Arrays.asList 入口

@SafeVarargs
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a); // 注意:這是 Arrays 內部類,非 java.util.ArrayList
}

2. 內部類 ArrayList 完整定義

private static class ArrayList<E> extends AbstractList<E> 
        implements RandomAccess, java.io.Serializable {
    private static final long serialVersionUID = -2764017481108945198L;
    private final E[] a; // 直接引用外部傳入的數組

    ArrayList(E[] array) {
        if (array == null) throw new NullPointerException();
        a = array;
    }

    // --- 僅實現只讀操作 ---
    public int size() { return a.length; }
    public E get(int index) { return a[index]; }
    public E set(int index, E element) { // 僅支持替換
        E old = a[index];
        a[index] = element;
        return old;
    }
    public int indexOf(Object o) { ... }
    public boolean contains(Object o) { return indexOf(o) != -1; }
    public Object[] toArray() { return a.clone(); }
    public <T> T[] toArray(T[] a) { ... }

    // --- 未重寫 add/remove/clear 等修改長度的方法 ---
    // 繼承自 AbstractList,默認拋出 UnsupportedOperationException
}

3. AbstractList 默認實現

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}
public E remove(int index) {
    throw new UnsupportedOperationException();
}
public boolean addAll(Collection<? extends E> c) {
    // 內部調用 add(),同樣拋出異常
}

設計意圖:固定大小的視圖

  • 零拷貝:直接包裝原始數組引用,構造 O(1)。
  • 語義明確:提供「數組 ↔ List」雙向適配,僅用於只讀遍歷、查找、替換元素場景。
  • 序列化支持:實現 Serializable、RandomAccess。

正確轉換為可變 List 的姿勢

// 方式 1:構造函數複製(推薦,語義清晰)
List<String> mutable = new ArrayList<>(Arrays.asList("A", "B", "C"));
mutable.add("D"); // OK

// 方式 2:Stream API(JDK 8+)
List<String> mutable = Stream.of("A", "B", "C")
    .collect(Collectors.toCollection(ArrayList::new));

// 方式 3:Collections.addAll(舊版本兼容)
List<String> mutable = new ArrayList<>();
Collections.addAll(mutable, "A", "B", "C");

常見誤區與避坑

誤區代碼後果修正
Arrays.asList(1,2,3).add(4)運行時拋異常外層包裹 new ArrayList<>(...)
List編譯錯誤:基本類型無法泛型化用 Integer 或 IntStream.of(...).boxed().collect(...)
修改返回 List 元素影響原數組list.set(0, "X") 會修改原數組若需隔離,先 Arrays.copyOf(arr, arr.length)

總結

Arrays.asList 返回的是固定大小、底層共享數組、僅支持 set/get/遍歷的 List 視圖。需要增刪操作時,務必拷貝構造新 ArrayList。理解此機制能避免線上「不可修改集合」異常。

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