记一次问题-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()]);

 

posted @ 2021-07-14 22:03  背着泰山找黄河  阅读(623)  评论(0编辑  收藏  举报