1. Arrays.asList的大坑以及正确使用方法
1.1 先抛出关于asList的使用的结论
-
基本数据类型的数组不要试图使用该方式转换为list,老老实实用for循环一个个加入list中去;引用数据类型的数组(包括二维数组)都可以采用该方式转换为list
//正确的转换方式 Integer[] arr = new Integer[n]; for(...)...//赋值 List<Integer> list = new ArrayList<>(Arrays.asList(arr));
-
如果只用于遍历,使用Arrays.asList(arr)即可;但是如果需要对list集合进行remover和add操作,就需要采用上述操作转换为util包下的ArrayList的方式了——所以,咱们倒不如每次都转换?害,看大家个人选择吧!
-
arrayList底层就是数组存储,而asList方式就是完成了浅拷贝的操作,因此使用set(int index, Object element)操作修改集合之后或者
1.2 源码分析
1.2.1 asList的浅拷贝操作分析
public static <T> List<T> asList(T... a) {
return new Arrays.ArrayList(a);//这里也可以看到,直接new的是Arrays的内部静态类:java.util.Arrays.ArrayList
}
//看到该有参构造器,直接将带转换的数组的引用传给Objects工具类的另外一个方法,该方法中将该ArrayList的数组a的引用赋值为待转换的数组,相当于返回的ArrayList和原数组指向的是同一份数据——浅拷贝
ArrayList(E[] array) {
this.a = (Object[])Objects.requireNonNull(array);
}
public static <T> T requireNonNull(T obj) {
if (obj == null) {
throw new NullPointerException();
} else {
return obj;
}
}
简单测试如下:
List<Integer> list = Arrays.asList(arr);
System.out.println("列表原内容为:");
for(int i : list)
System.out.print(i + " ");
System.out.println();
System.out.println("******************");
System.out.println("数组原内容为:");
for(int i : arr)
System.out.print(i + " ");
System.out.println();
System.out.println("******************");
list.set(1, 10);//更新列表内容:虽然没有add和remove方法,但是存在set方法可以按照位序修改元素
System.out.println("列表内容更新为:");
for(int i : list)
System.out.print(i + " ");
System.out.println();
System.out.println("******************");
System.out.println("数组遍历结果更新为:");
for(int i : arr)
System.out.print(i + " ");
System.out.println();
列表原内容为:
0 1 2 3 4
******************
数组原内容为:
0 1 2 3 4
******************
列表内容更新为:
0 10 2 3 4
******************
数组遍历结果更新为:
0 10 2 3 4
******************
通过上面简单的测试我们发现:是浅拷贝而已,修改列表内容原数组内容也会跟着修改。
1.2.2 新生成的List实例并非java.util.ArrayList的实例
上图可以明显看到,asList生成的ArrayList仅仅是Arrays的一个内部静态类的实例java.util.Array.ArrayList!而非java.util.ArrayList!
且该ArrayList不存在add和remove方法,如果进行增删的话会报错!