记一次问题-Arrays.asList()和 new ArrayList<>()的区别以及导致数组类型转换异常的解决Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
问题代码如下:
public static void main(String[] args) { Integer[] intArr={9,4,7,8,4,6};
//第一种创建ArrayList方式 List<Integer> intOldList = Arrays.asList(intArr);
//第二种创建ArrayList方式
List<Integer> intNewList = new ArrayList<>(); intNewList.add(9); System.out.println(intOldList.toArray().getClass().getSimpleName()); System.out.println(intNewList.toArray().getClass().getSimpleName()); Integer [] toArrayOld = (Integer[]) intOldList.toArray(); //这一行 类型转换异常 Integer [] toArrayNew = (Integer[]) intNewList.toArray(); }
打印结果:
Integer[] Object[] Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer; at test.main(test.java:13)
到这里有人在想了,两种方式最后的结果都是创建ArrayList,为什么有一个能够转换成功,有一个就不能转换成功呢???
虽然展示给咱们的感觉是相同的,但是咱们通过intOldList.toArray().getClass().getSimpleName()方法获取源代码底层类的名称,得到的结果确实不一样的,一个Integer[]一个Object[],这又是为什么呢???
其实到这里已经说明了问题原因,两者的类型就是不一样的,所以一个正常转换,一个类型转换异常,Object[]不能直接强转为Integer[],如果想深究,那么请往下看。
以上代码总结出以下两点
1、Arrays.asList转换过来的ArrayList和直接new出来的ArrayList是不一样的
两个集合类,一个是通过数组工具类的Arrays.asList转换而来的,一个是直接new出来的。打印出来的结果却不一样,一个是Integer[],一个是Object[]。最后第二个直接new出来的在类型转换时还报了异常。
原因如下:
Arrays.asList返回的是Arrays中的内部类ArrayList,可以直接点击该方法,查找源代码。
/** * @serial include */ 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); } ......省略部分代码 }
但是直接new出来直接就是ArrayList,两者是不一样的。两者根源的不一样又导致两个类的toArray方法的不一样,具体请看以下截图说明:
首先来说一说在ArrayList这个类源码中的toArray方法
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
transient Object[] elementData;
可以看出,其实在ArrayList中直接调用的Arrays.copyOf方法,里面的参数elementData,是一个Object的数组,在这里我个人认为是做了一次类型擦除。也是由于在这里,将Integer类型的数组转换为Object类型的数组。
然后来说一说Arrays中的toArray方法
public Object[] toArray() { return a.clone(); }
可以看出,这里直接用的Object的底层clone方法,这样就保持了原来的数组类型。
2、扩展,接下来说说ArrayList的toArray方法的使用
ArrayList提供了一个将List转为数组的一个非常方便的方法toArray。toArray有两个重载的方法: (1)list.toArray(); (2)list.toArray(T[] a); 第一个重载方法,是将list直接转为Object[] 数组; 第二个方法是将list转化为你所需要类型的数组,当然我们用的时候会转化为与list内容相同的类型。
第一个方法如下写法:
ArrayList<String> list=new ArrayList<String>(); for (int i = 0; i < 10; i++) { list.add(""+i); } String[] array= (String[]) list.toArray();
运行就会报错:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
原因是:不能将Object[] 直接通过以上例子中类型强转换的方式转化为String[],转化的话只能是取出每一个元素再转化。像这样:
Object[] arr = list.toArray(); for (int i = 0; i < arr.length; i++) { String e = (String) arr[i]; System.out.println(e); }
第二个方法如下写法:
String[] array =new String[list.size()]; list.toArray(array);
运行正常。
结论:建议使用带参数的转换方式
集合转数组用方法,比如:list.toArray(new String[list.size()]);
利用set去重list重复数据转数组:set.toArray(new String[set.size()]);