c.toArray might (incorrectly) not return Object[] (see 6260652)

747 阅读1分钟

看ArrayList源码的时候,无意中看到了下面的代码:

public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

其中:c.toArray might (incorrectly) not return Object[] (see 6260652)深深吸引到了我。 去官网上看了关于此问题的描述:Arrays.asList(x).toArray().getClass() should be Object[].class 我自己运行了个网上的demo:

 public static void test2() {
        List<String> list = Arrays.asList("123");// class java.util.Arrays$ArrayList
        System.err.println(Arrays.asList("123").toArray().getClass());
        Object[] objArray = list.toArray();
        System.out.println(objArray.getClass());  // class [Ljava.lang.String;
        objArray[0] = new Object(); // cause ArrayStoreException
    }

然后发现没有报错,看了下我的jdk是11,然后换了jdk8果然报错了,比较了下区别,jdk8是

 @Override
        public Object[] toArray() {
            return a.clone();
        }

而jdk11是:

 public Object[] toArray() {
            return Arrays.copyOf(this.a, this.a.length, Object[].class);
        }

所以jdk11版本Arrays.asList(x).toArray().getClass()会返回Object.class,所以之前的测试代码在不同版本会返回不同接口。 但Jdk11的ArrayList代码里面依旧会提示一开始的提示,这是为什么呢? 这其实就是java对象的向上转型,子类数组转换成父类数组是允许的所以一个object[]数组,并不代表里面存放的元素就一定是object类型的,所以不判断的话会报错,举个例子:

 class myList extends ArrayList<String> {

        @Override
        public String[] toArray() {
            return new String[]{"1", "2", "3"};
        }
    }
    
      List<String> list = new myList();
        System.err.println(list.toArray().getClass());
        list.toArray()[0]=new Object();

这里会报类型转换错误 所以类推ArrayList里面不进行if判断的话,也同样可能会报这个错误,所以java真的是博大精深,越看源码越觉得自己很菜。