成员
构造器
public ArrayList(Collection<? extends E> c)
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); //~ c 也是一个集合, c.toArray() 是一个 Object[] 数组
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; //~ 如果是空数组则引用 EMPTY_ELEMENTDATA
}
}
这里有一个有意思的点是 line2, 首先, c
是一个集合, c.toArray()
是一个数组, 在 Collection
这个接口中规定了 toArray()
这个方法返回的是 Object[]
数组, 而实现接口并重写方法有两种情况:
- 实现类返回值不变, 还是
Object[]
数组; - 实现类返回值改变, 比如改成
String[]
数组;
而根据数组引用这一篇文章, 我们知道, 数组可以引用其元素类型子类的数组对象(相当于数组的多态), 而 Object 又是所有类的父类, 所以上面两种情况在这个构造器的 line2 都看上去没有问题, 我们举两个例子:
@Test
public void test() {
Object[] objs1 = new MyArrayList1().toArray(); // 正常引用
System.out.println(objs1.getClass()); // class [Ljava.lang.String;
Object[] objs2 = new MyArrayList1().toArray(); // 正常引用
System.out.println(objs2.getClass()); // class [Ljava.lang.String;
}
class MyArrayList1 extends ArrayList{
@Override
public Object[] toArray() {
return new String[]{"1", "2", "3"};
}
}
class MyArrayList2 extends ArrayList{
@Override
public String[] toArray() {
return new String[]{"1", "2", "3"};
}
}
可以发现构造器的 line2 引用没问题, 但是有一个问题是, 在上面代码块的 Object[] objs1
和 Object[] objs2
的类型都变成了 class [Ljava.lang.String
, 也就是说, 现在, obj1 和 obj2 都只能存放字符串(或其子类, 当然, 字符串没有子类)了:
objs1[0] = new Son(); // java.lang.ArrayStoreException
objs2[1] = new Father(); // java.lang.ArrayStoreException
这就是大 Bug 了, 好好的 Object[]
数组怎么就功能锐减了, 这不行, 所以源码才说:
c.toArray might (incorrectly) not return Object[] (see 6260652)
并进行了判断, 如果为空则引用其内的静态空数组, 如果非空, 判断其数组类型是不是 Object[]
, 不是的话调用 Arrays.copyOf()
浅拷贝一个 Object[]
数组, 这样就可以存储任何类型的数据了.
看了下 JDK11 仍然是这样的写法, 所以说这只能说是 Java 本身的机制问题了.
问题
modCount:
https://www.cnblogs.com/zuochengsi-9/p/7050351.html
grow():
大整数 * 1.5 变负数.