看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真的是博大精深,越看源码越觉得自己很菜。