ArrayList源码解析!
发表于更新于
编程语言JavaArrayList源码解析!
月伴飞鱼ArrayList整体架构是一个数组结构:

基本概念:
DEFAULT_CAPACITY
:表示数组的初始大小,默认是 10。
size:表示当前数组的大小,类型是 int,没有使用 volatile 修饰,非线程安全。
modCount:统计当前数组被修改的版本次数,数组结构有变动,就会加 1。
初始化
ArrayList无参构造器初始化时,默认大小是空数组,并不是默认的DEFAULT_CAPACITY
10,10 是在第一次 add 时扩容的值。
新增
判断是否需要扩容,如果需要则执行扩容操作。
赋值新元素。
1 2 3 4 5 6 7
| public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; return true; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
private void ensureExplicitCapacity(int minCapacity) { modCount++;
if (minCapacity - elementData.length > 0) grow(minCapacity); }
private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }
|
扩容的规则并不是翻倍,而是 原来容量大小 + 原来容量大小的一半(原来容量的 1.5 倍)。
ArrayList 中数组的最大容量是 Integer.MAX_VALUE
,超过这个值,JVM 就不会给数组分配内存空间了。
新增时,并没有对值进行严格的校验,所以 ArrayList 是允许 null 值的。
扩容
扩容会先新建一个符合我们预期容量 newCapacity
的新数组,然后把旧数组的数据拷贝过去。
1 2 3 4 5 6 7 8
| public static int[] copyOf(int[] original, int newLength) { int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
|
线程安全
只有当 ArrayList
作为共享变量时,才会有线程安全问题,当 ArrayList
是方法内部局部变量时,是没有线程安全问题的。
本质是因为 ArrayList 自身的 elementData、size、modCount 在进行各种操作时,都没有加锁。
而且这些变量的类型并非是可见的(volatile)的,所以如果多个线程对这些变量进行操作时,可能会有值被覆盖的情况。