Arrays.asList(arr) 几乎是每个 Java 开发者都用过的方法,但"它返回的到底是不是一个真正独立的 List"这个问题,真实验证一次比记住结论更靠得住。
上一篇:Arrays.sort 的稳定性:真实验证 Object[] 排序会保留相同分数的原始顺序
Arrays.asList() 返回的是 java.util.Arrays 内部的一个私有 ArrayList 实现,它内部持有的就是传进来的那个数组引用本身,不是拷贝。
view = [1, 2, 3, 4, 5] view.set(0, 999) 之后: view = [999, 2, 3, 4, 5] backing = [999, 2, 3, 4, 5](原始数组是否真的被改了?) 直接改 backing[1] = 888 之后: backing = [999, 888, 3, 4, 5] view = [999, 888, 3, 4, 5](view 是否也跟着变了?)
两个方向的真实数据都确认了同一件事:view 和 backing 共享同一份底层存储,改任何一边,另一边都会真实同步反映出来。这和系列前面Collections.unmodifiableList 那篇的"视图不是拷贝"是同一类问题,只是这次视图本身还允许 set。
虽然允许 set(替换已有位置的元素),但 Arrays.asList() 返回的是固定大小视图,不允许改变长度。
view.add(6) 真实抛出 UnsupportedOperationException view.remove(0) 真实抛出 UnsupportedOperationException
原因很直接:底层数组的长度在创建时就已经固定,add/remove 需要真实改变元素个数,而数组本身做不到这一点(Java 数组一旦创建长度不可变)——Arrays.asList() 返回的这个内部类没有重写 add/remove,直接继承了 AbstractList 里默认的、真实抛出 UnsupportedOperationException 的实现。
如果确实需要一个可以自由增删、又不影响原始数组的 List,标准做法是把 asList 的结果再包一层 ArrayList 构造函数。
new ArrayList<>(Arrays.asList(backing)) 得到真正的 ArrayList,add(777) 成功: [999, 888, 3, 4, 5, 777] 对原始 backing 数组真实没有任何影响 = [999, 888, 3, 4, 5]这次 add 真实成功了,且原始数组真实没有被这次操作影响——因为 ArrayList 的这个构造函数会把传入集合的元素真实拷贝进一个新分配的内部数组
每一步的数组内容都是真实运行这段代码之后的状态,不是手工画的联动关系。