Arrays.asList()返回的是Arrays.ArrayList而非java.util.ArrayList,其add等修改结构的方法抛UnsupportedOperationException;仅get、set、size等不改变长度的操作可用;需增删时应new ArrayList包装。

Arrays.asList() 返回的不是 java.util.ArrayList
调用 Arrays.asList() 得到的 List 实际是 java.util.Arrays.ArrayList —— 这是 Arrays 类里的一个私有静态内部类,和大家日常用的 java.util.ArrayList 完全无关。它不继承自后者,也没有扩容逻辑、不维护 elementData 和 size 字段的动态关系,只持有一个 final E[] a 引用,直接绑定原始数组。
add() 方法没被重写,走的是 AbstractList 的默认实现
Arrays.ArrayList 继承自 AbstractList,但源码里明确没重写 add(int, E)、remove(int)、clear() 等方法。所以一调用 add(),就落到 AbstractList.add() 上,而它的实现只有一行:
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
这不是疏漏,是 JDK 故意为之的设计:这个列表只是数组的“视图”,结构必须和原数组严格一致。
哪些操作能用?为什么 set() 可以但 add() 不行?
set() 能用,是因为它只改原数组某个下标的值,不改变长度;get()、size()、contains() 也安全,它们不修改结构。但任何影响 size 或元素索引连续性的操作都会失败,包括:
立即学习“Java免费学习笔记(深入)”;
-
add()、addAll() -
remove()、removeAll()、retainAll() clear()
注意:toArray() 看似“复制”,其实返回的是原数组的克隆(a.clone()),不影响原数组,所以不抛异常。
想增删怎么办?别绕开,直接兜底转换
最直接的办法就是用 new ArrayList(Arrays.asList(...)) 包一层。这会把不可变视图的数据拷进真正的 java.util.ArrayList 实例中,后续所有增删改查都正常。
别试图用 Collections.unmodifiableList() 或反射去“修复”——前者更不可变,后者破坏封装且无必要。真正需要可变行为时,构造新实例是最清晰、最符合语义的做法。
容易忽略的一点是:即使你只调用 set(),改动也会同步反映到原始数组上。如果原数组生命周期长或被多方共享,这点副作用得提前意识到。


















