Arrays.asList()返回的是Arrays的私有内部类ArrayList,非java.util.ArrayList,它基于final数组实现,只支持读取和set操作,add/remove等会抛UnsupportedOperationException;修改原数组或List元素会双向同步。

Arrays.asList 返回的不是你熟悉的 ArrayList
调用 Arrays.asList() 得到的 List,表面看是 List 接口实例,实际是 java.util.Arrays 类里的一个私有静态内部类:Arrays.ArrayList。它和 java.util.ArrayList 同名但毫无关系——既不继承它,也不共享行为。这个内部类直接持有一个 final 引用的原始数组,所有操作都基于该数组展开,没有扩容、不支持结构变更。
增删方法根本不存在,靠父类兜底抛异常
这个内部类继承自 AbstractList,但只重写了 get()、set()、size()、indexOf() 等读取和定位方法;而 add()、remove()、clear() 等修改结构的方法完全没重写。于是运行时会落到 AbstractList 的默认实现上:
public void add(int index, E element) { throw new UnsupportedOperationException(); }public E remove(int index) { throw new UnsupportedOperationException(); }
所以一调就崩,异常类型固定为 UnsupportedOperationException,不是空指针,也不是越界,而是“明确拒绝”。
原始数组与 List 是双向绑定的
因为内部类持有的是原数组的直接引用(且是 final E[] a),所以:
- 修改原数组某个位置的值,
asList返回的 List 对应下标也会立刻反映变化 - 反过来,通过
set(i, x)修改 List 元素,等价于改原数组 —— 这是唯一被允许的“写”操作 - 但任何试图改变长度的操作(如
add、remove、addAll)都会失败
如何安全使用?关键在“包装”
如果业务需要后续增删,必须显式构造一个真正可变的集合:
- 正确写法:
new ArrayList(Arrays.asList("a", "b", "c")) - 或用 Java 10+ 的
List.copyOf()(返回不可变副本,适合只读场景) - 对基本类型数组(如
int[])要格外小心:它会被整体当作单个元素,导致 size=1;应先转成包装类型数组或用Stream.boxed()
不复杂但容易忽略










