一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
ArrayList源码分析-初始化
ArrayList是我们经常会用到的一个类,并且也属于面试常问的问题。
ArrayList底层结构
先看源码:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access
private int size;
......
}
ArrayList底层就是一个数组,其中:
- DEFAULT_CAPACITY 表示数组的初始大小,默认为 10
- size 表示当前数组的大小
- modCount 统计当前数组被修改的版本次数,每次数组结构有变动时,例如调用add()、remove(),modCount的值就会跟随 +1。
ArrayList其他特点,也是注释上的说明:
- ArrayList内允许放入null值
- 新增元素时会有扩容机制
- 是非线程安全的
- 增强 for 循环,或者使用迭代器迭代过程中,如果数组大小被改变,会快速失败,抛出异常。
ArrayList的初始化方法
无参初始化,源码:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
指定大小初始化,源码:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
指定初始化数据初始化,源码:
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;
}
}
需要注意的是,其中ArrayList 无参构造器初始化时,默认大小是空数组,并不是大家常说的 10,10 是在第一次 add 的时候扩容的数组值。
初始化中的一个bug
在以上构造方法的指定初始数据初始化方法中,有一行注释 see 6260652,这是 Java 的一个 bug。
当初始化数据传入值不是Object类型时,转为Object,调用java.util.ArrayList#toArray()方法,得到Object数组,往Object数组赋值时会触发此bug,不过已经在java9版本中修复。