一.引言:
实际操作中,我们会遇到需要将数组转化为list的情况,这个时候我们可以借助Java的Arrays类的方法进行便捷操作,接下来来看以下操作的例子:
Integer[] arr= {1, 2, 3};//1
List<Integer> list = new ArrayList<>(Arrays.asList(arr));//2
list.add(4);
System.out.println(list.toString());
结果如下:
[1, 2, 3, 4]
接下来让我们来看下经常出现的两种方式的情况。
二.定义数组的类型为包装类型或者是基本类型?
我们来看下面一个例子:
int[] arr1= {1, 2, 3};
Integer[] arr2 = {1, 2, 3};
List<int[]> list1 = new ArrayList<>(Arrays.asList(arr1));
List<Integer> list2 = new ArrayList<>(Arrays.asList(arr2));
System.out.println("基本类型转化后的集合大小为:"+list1.size()+
"\n包装类型转化后的集合大小为:"+list2.size());
输出结果为:
基本类型转化后的集合大小为:1
包装类型转化后的集合大小为:3
分析:
我们看一下asList()方法,
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
可以看到他的参数为T,我们来简单普及下java泛型T,泛型T本质是Object类型 ,是引用类型 ,不包括基本类型,int这种基本类型不是。我们知道任何类型的对象都有一个 class 属性,这个属性代表了这个类型本身。原生数据类型,比如 int,short,long等,是没有这个属性的,具有 class 属性的是它们所对应的包装类 Integer,Short,Long。
因此,这个错误产生的原因可解释为:asList 方法的参数必须是对象或者对象数组,而原生数据类型不是对象——这也正是包装类出现的一个主要原因。当传入一个原生数据类型数组时,asList 的真正得到的参数就不是数组中的元素,而是数组对象本身!此时List 的唯一元素就是这个数组。
ps:从两个数组转化为list,IDEA自动生成的实例化对象也可以观察到,Integer是List,而int的是List<int[]>,因此包装类型的list还是包装类型,而基本类型的list是放入了他对应的数组。
三. 该如何修改list的大小
我们来看下面一个例子:
Integer[] arr1= {1, 2, 3};
List<Integer> list1 = Arrays.asList(arr1);
list1.add(4);
System.out.println(list1);
输出结果为:
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.test.main(test.java:17)
我们查看asList方法的描述,出现一句:
Returns a fixed-size list backed by the specified array.
意思是:返回由指定数组支持的固定大小列表。
接着查看asList方法调用的ArrayList()方法:
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
//...
}
分析:
直接使用asList()生成的list固定了集合的大小,不能实现add,remove等操作。
原因在于asList调用了一个静态表内部类ArrayList,在这个内部类中有一个被声明为 final 的数组 a ,所有传入的元素都会被保存在这个数组 a 中。到此,谜底又揭晓了: asList 方法返回的确实是一个 ArrayList ,但这个 ArrayList 并不是 java.util.ArrayList ,而是 java.util.Arrays 的一个内部类。这个内部类用一个 final 数组来保存元素,因此用 asList 方法产生的 ArrayList 是不可修改大小的。
因此需要创建一个真正的List,
List list = new ArrayList<>(Arrays.asList(arr)),
在上面这段代码中,我们 new 了一个 java.util.ArrayList ,然后再把 asList 方法的返回值作为构造器的参数传入,最后得到的 myList 自然就是可以动态扩容的了。
四.总结
- asList()适用于将数组转化为list的一个工具类;
- asList()转化为数组最好是包装类型或者是引用类型的;
- asList()转化为数组时,最好创建一个真正的ArrayList,方便后续的add,remove等操作。