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

基本概念:
DEFAULT_CAPACITY:表示数组的初始大小,默认是 10。
size:表示当前数组的大小,类型是 int,没有使用 volatile 修饰,非线程安全。
modCount:统计当前数组被修改的版本次数,数组结构有变动,就会加 1。
初始化
ArrayList无参构造器初始化时,默认大小是空数组,并不是默认的DEFAULT_CAPACITY 10,10 是在第一次 add 时扩容的值。
新增
判断是否需要扩容,如果需要则执行扩容操作。
赋值新元素。
| 12
 3
 4
 5
 6
 7
 
 | public boolean add(E e) {
 ensureCapacityInternal(size + 1);
 
 elementData[size++] = e;
 return true;
 }
 
 | 
| 12
 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 的新数组,然后把旧数组的数据拷贝过去。
| 12
 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)的,所以如果多个线程对这些变量进行操作时,可能会有值被覆盖的情况。