一般情况下,使用Arrays.asList()的原因无非是想将数组或一些元素转为集合,而你得到的集合并不一定是你想要的那个集合。
asList在最初设计时用于打印数组,但jdk1.5开始,有了另一个比较更方便的打印函数Arrays.toString(),于是打印不再使用asList(),而asList()恰巧可用于将数组转为集合。
一、首先看几个例子:
(1)将基本类型数组作为asList参数
String[] strArr = {"A","B","C"};
List<String> asList = Arrays.asList(strArr);
System.out.println("封装类型String时:" + asList.size());
int[] intArr = {1, 2, 3};
List<String> list = Arrays.asList(intArr);
System.out.println("基本类型时:" + list.size());
运行结果:
封装类型String时:3
基本类型时:1
(2)将数组作为asList参数后,修改数组或List
String[] strArr = {"A","B","C"};
List<String> asList = Arrays.asList(strArr);
strArr[0] = "a";
asList.set(1, "b");
System.out.println(Arrays.toString(strArr));
System.out.println(asList.toString());
运行结果:
[a, b, C]
[a, b, C]
strArr和asList 中的数据都会改变
(3)数组转换为集合后,进行增删元素
String[] strArr = {"A","B","C"};
List<String> asList = Arrays.asList(strArr);
asList.add("1");
asList.remove("C");
System.out.println(asList.toString());
运行结果:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at com.my.tests.TestArrayAsList.main(TestArrayAsList.java:9)
二、深入研究
这里要关注的地方在于:
Arrays.asList()返回的List是:Arrays.ArrayList,而不是java.util.ArrayList
两者的不同之处:
Arrays.ArrayList是工具类Arrays的一个内部静态类,它没有完全实现List方法,而ArrayList直接实现了List接口,实现了List所有方法。
- 长度不同和实现的方法不同:
Arrays.ArrayList是一个定长集合,因为它没有重写add,remove方法,所以,一旦初始化元素后,集合的size就是不可变的。 - 参数赋值方式不同
Arrays.ArrayList将外部数组的引用直接通过“=”赋予内部的泛型数组,所以本质指向同一个数组。而ArrayList是将其他集合转为数组后copy到自己内部的数组的。
// 以下是JDK8版本中的Arrays.ArrayList
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array); // 此处是直接赋值的,所以本质指向的是同一个数组
}
}
// 以下是JDK8中java.util.ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); // toArray底层使用的是数组clone或System.arraycopy
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
三、案例解析
对于第一个例子:(1)将基本类型数组作为asList参数
由于Arrays.ArrayList参数为可变长泛型,而基本类型是无法泛型化的,所以它把int[] arr数组当成了一个泛型对象,所以集合中最终只有一个元素arr。
对于第二个例子:(2)将数组作为asList参数后,修改数组或List
由于asList产生的集合元素是直接引用作为参数的数组,所以当外部数组或集合改变时,数组和集合会同步变化,这在平时我们编码时可能产生莫名的问题。
对于第三个例子:(3)数组转换为集合后,进行增删元素
由于asList产生的集合并没有重写add,remove等方法,所以它会调用父类AbstractList的方法,而父类的方法中抛出的却是异常信息。
四、支持基础类型的方式
1、如果使用Spring
import org.springframework.util.CollectionUtils;
public class Temp {
public static void main(String[] args) {
int[] arr = {1,2,3};
List list = CollectionUtils.arrayToList(arr);
System.out.println(list);
}
}
运行结果:
[1, 2, 3]
2、直接使用Java8
int intArray[] = {1,2,3};
List<Integer> iList = Arrays.stream(intArray)
.boxed()
.collect(Collectors.toList());
System.out.println(iList);
运行结果:
[1, 2, 3]
五、数组转ArrayList
1、遍历转换
Integer intArray[] = {1,2,3};
ArrayList<Integer> arrayList = new ArrayList<>();
for (Integer i : arrayList) {
arrayList.add(i);
}
2、使用工具类(更加优雅)
ArrayList<String> list = new ArrayList();
Collections.addAll(list, "A", "B", "C");
3、对于JAVA8
既可以用于基本类型也可以返回想要的集合。
int intArray[] = {1,2,3};
List<Integer> iList = Arrays.stream(intArray)
.boxed()
.collect(Collectors.toList());
System.out.println(iList);
运行结果:
[1, 2, 3]
4、还有另外一种方法
两个集合类结合:将Arrays.asList返回的集合作为ArrayList的构造参数
ArrayList arrayList = new ArrayList<>(
Arrays.asList("A", "B", "C")
);