1. 问题说明
记录一下遇到的这个bug,下面是段个简化后的问题重现代码。
public class Test {public static void main(String[] args) {List<Integer> list = Arrays.asList(1, 2, 3);list.add(4);}
}
2. 原因分析
我们看一下Arrays.asList(…) 的源码:
/*
- Returns a fixed-size list backed by the specified array. Changes made to the array will be visible in the returned list, and changes made to the list will be visible in the array. The returned list is Serializable and implements RandomAccess.
- The returned list implements the optional Collection methods, except those that would change the size of the returned list. Those methods leave the list unchanged and throw UnsupportedOperationException.
- If the specified array's actual component type differs from the type parameter T, this can result in operations on the returned list throwing an ArrayStoreException.
*/
@SafeVarargs
/varargs/
public static <T> List<T> asList(T... a) {return new ArrayList<>(a);
}
// 上面的 return new ArrayList<>(a)中的ArrayList源码
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { // ...
}
从方法上给出的注释信息中的第2条可以知道,返回的其实是 java.util.Arrays$ArrayList
(也就是一个内部类,并不是 java.util.ArrayList
)。它内部基于数组实现,只能固定大小,不支持 add()
、addAll()
、remove()
等结构性操作 。如果如果你需要一个可变、可以添加或删除元素的列表,请用:
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
list.add(3); // 安全可行
3. 补充说明
- 在高并发或多线程环境下,如果基础数组发生变化,
Arrays.asList
返回的列表内容也会变化,可能引发数据不一致。 List.of(...)(Java 9+)
是完全不可变的列表,任何变结构操作都会立即抛异常;而 Arrays.asList 是“可修改元素但不可改大小”。