项目中经常使用Arrays.asList方法方便的得到的list,发现有很多细节的知识点可以总结一下,总结的注意事项有以下几点:
1)通过Arrays.asList方法得到的list是固定大小的,不可以add或remove方法去改变list的元素
2)不支持基础数据类型的转换
3)改变原始数组的内容或者改变通过Arrays.asList方法得到的list的元素值值,相互之间的数据都会自动更新,因为这个方法是将数组和列表链接起来
下面来通过测试解释一下原因:
1)通过Arrays.asList方法得到的list是固定大小的,不可以add或remove方法去改变list的元素
看源码我们可以看到Arrays.asList是通过Arrays的一个内部类ArrayList实现的,这个内部类继承自AbstractList同时实现了RandomAccess和Serializable接口,所以这里得到的
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable
继承的AbstractList中对add、remove、set方法是直接抛异常的,也就是说如果继承的子类没有去重写这些方法,那么子类的实例去调用这些方法是会直接抛异常的
下面是AbstractList中方法的定义,我们可以看到具体抛出的异常:
public void add(int index, E element) { throw new UnsupportedOperationException(); }
public E remove(int index) { throw new UnsupportedOperationException(); }
public E set(int index, E element) { throw new UnsupportedOperationException(); }
我们来验证一下结论是不是这样的,转换之后我们调用一下add方法:
public class ArraysListTest { public static void main(String[] args) { Integer[] a_Integer= new Integer[] { 1, 2, 3, 4 }; List a_Integer_List = Arrays.asList(a_Integer); a_Integer_List.add(5); } }
看下运行的结果:
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(AbstractList.java:148) at java.util.AbstractList.add(AbstractList.java:108)
抛出来异常和AbstractList中add方法定义抛出来的异常是一样,也验证了是不可操作的
那我们再验证一下set方法,再获取到list后,通过set方法去改变第一个元素的值,测试用例如下:
public class ArraysListTest { public static void main(String[] args) { Integer[] a_Integer= new Integer[] { 1, 2, 3, 4 }; List a_Integer_List = Arrays.asList(a_Integer); a_Integer_List.set(0,888); foreach(a_Integer_List); } /*打印方法*/ private static void foreach(List list) { for (Object object : list) { System.out.println(object + " "); } System.out.println(); } }
看戏运行结果:
888 2 3 4
不仅没有抛异常,还能做到改变第一个元素的值,这是为什么呢?结论是Arrays内部定义的内部类ArrayList重写了set方法,使得set功能是可以操作的
@Override public E set(int index, E element) { E oldValue = a[index]; a[index] = element; return oldValue; }
2)不支持基础数据类型的转换
Java中的基础数据类型(byte,short,int,long,float,double,boolean)是不支持使用Arrays.asList方法去转换的
首先看下Arrays.asList方法的定义:
public static <T> List<T> asList(T... a) {}
参数类型是一个T,根据官方文档的描述,T 是数组元素的 class
public class ArraysListTest { public static void main(String[] args) { int [] a_int = { 1, 2, 3, 4 }; /*预期输出应该是在1,2,3,4,但实际上输出的仅仅是一个引用,这里它把a_int 当成一个元素*/ List a_int_List = Arrays.asList(a_int); foreach(a_int_List); /*为此我们需要这样遍历其中元素*/ foreachForBase(a_int_List); } /*打印方法*/ private static void foreach(List list) { for (Object object : list) { System.out.println(object + " "); } System.out.println(); } private static void foreachForBase(List a_int_List) { int[] _a_int = (int[]) a_int_List.get(0); foreach(_a_int); } private static void foreach(int[] a_int) { for (int i : a_int) { System.out.println(i + " "); } System.out.println(); } }
[I@36f6e879
1
2
3
4
我们可以看到第一个打印出来的结果是数组对象的hashcode值,并不是真正数组元素。
3)改变原始数组的内容或者改变通过Arrays.asList方法得到的list的元素值值,相互之间的数据都会自动更新,因为这个方法是将数组和列表链接起来
当我们去改变其中的list或者数组的元素时,两个是同时改变的,转后list后,我们改变list中元素的值,再看下数组的值:public class ArraysListTest { public static void main(String[] args) { Integer[] a_Integer= new Integer[] { 1, 2, 3, 4 }; List a_Integer_List = Arrays.asList(a_Integer); a_Integer_List.set(0,888); foreach(a_Integer_List); foreach(a_Integer); } /*打印方法*/ private static void foreach(List list) { for (Object object : list) { System.out.println(object + " "); } System.out.println(); } private static void foreach(Integer[] _a_Integer) { for (int i : _a_Integer) { System.out.println(i + " "); } System.out.println(); } }
看下运行的效果:
888 2 3 4 888 2 3 4
可以看到数组的值也跟着改变了,发过来改变数组的值,list元素的值也是变更的,因为asList获得List实际引用的就是数组
最后,如果我们想得到一个真正的可操作的list通过什么方法呢?
第一种最简便的方式:new 一个真正的java.util.ArrayList
List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3));
第二种使用Java8的stream方式:
Integer [] myArray = { 1, 2, 3 }; List myList = Arrays.stream(myArray).collect(Collectors.toList()); //基本类型也可以实现转换(依赖boxed的装箱操作) int [] myArray2 = { 1, 2, 3 }; List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());
原文:https://www.cnblogs.com/wangflower/p/12452355.html