zoukankan      html  css  js  c++  java
  • 记一次问题-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()]);
  • 相关阅读:
    如何修改注册表立刻生效【搜藏】
    c#怎样让picturebox出现滚动条【搜藏】
    c#怎样让程序运行出错仍继续执行【原】
    marquee标签里文本的自动换行【搜藏】
    关于HyperLink的NavigateUrl属性的链接地址带参数出错的问题【整理】
    C#程序获得星期【整理】
    sql分别获取年/月/日 函数【搜藏】
    获取本周属于本年度第几周【搜藏】
    关于ref 和 out 关键字【整理】
    hdu 1823 Luck and Love
  • 原文地址:https://www.cnblogs.com/qcq0703/p/15013210.html
Copyright © 2011-2022 走看看