数组与集合都是用来存储对象的容器,前者性质单一,方便易用;后者类型安全,功能强大,且两者之间必然有相互转化的方式。毕竟他们性格迥异,在转换过程中,如果不注意转换背后的实现方式,很容易产生意料之外的问题。转换分成两种情况:数组转集合和集合转数组。
1、数组转集合
在数组转集合的过程中,注意是否使用了视图方式直接放回数组中的数据。我们以 Arrays.asList() 为例,它把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。实例源码如下:
public class ArrayAsList {
public static void main(String[] args) {
String[] stringArray = new String[3];
stringArray[0] = "one";
stringArray[1] = "two";
stringArray[2] = "three";
List<String> stringList = Arrays.asList(stringArray);
// 修改转换后的集合,成功地将第一个元素"one"改成"oneList"
stringList.set(0,"oneList");
// 运行结果是"oneList",数组的值随之更改
System.out.println(stringArray[0]);
// 这是重点:以下三行编译正确,但都会跑抛出运行时异常
stringList.add("four");
stringList.remove(2);
stringList.clear();
}
}
事实证明,可以通过set方法修改元素的值,原有数组相应位置的值同时也会被修改,但是不能进行修改元素的任何操作,否则均会抛出 UnsupportedOperationException 异常。 Arrays.asList 体现的是适配器模式,后台的数据仍是原数组, set() 方法即间接对数组进行值的修改操作。 asList 的返回对象是一个 Array 的内部类,它并没有实现集合个数的相关修改方法,这也正是抛出异常的原因。
2、集合转数组
相对于数组转集合来说,集合转数组更加可控,毕竟是从相对自由的集合容器转为更加苛刻的数组。什么情况下集合需要转成数组呢?适配别人的接口,或者进行局部方法计算等。先看一个源码,猜猜执行结果:
public class ListToArray {
public static void main(String[] args) {
List<String> list = new ArrayList<String>(3);
list.add("one");
list.add("two");
list.add("three");
// 范型丢失,无法使用String[]接收无参方法返回的结果(第1处)
Object array1 = list.toArray();
// array2数组长度小于元素个数(第2处)
String[] array2 = new String[2];
list.toArray(array2);
System.out.println(Arrays.asList(array2));
// array3数组长度等于元素个数(第3处)
String[] array3 = new String[3];
list.toArray(array3);
System.out.println(Arrays.asList(array3));
}
}
执行结果如下:
[null,null]
[one,two,three]
第1处比较容易理解,不要用 toArray() 无参方法把集合转换成数组,这样会导致范型丢失;在第2处与第3处的区别在于即将复制进去的数组容量是否足够。如果容量不够,则弃用此数组,另起炉灶。