JDK10 ArrayList add 扩容怎么实现的(解析源码记录篇)?
翻阅源码,初学源码,如有不对,请多指教
无参构造方法
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
无参构造方法 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
声明调用DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
带参构造方法
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
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);
}
}
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
带参构造方法
参数
initialCapacity - 列表的初始容量
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// defend against c.toArray (incorrectly) not returning Object[]
// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
重点来了 add
添加当单个元素使用的方法为 public boolean add(E e)
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
进行数组赋值时,先会去修改数组的长度
private Object[] grow() {
return grow(size + 1);
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
// 进行拷贝数组
// newCapacity(minCapacity) 拷贝的新数组的长度
// 使用copyOf截取原数组,并返回带新长度的数组
return elementData = Arrays.copyOf(elementData,newCapacity(minCapacity));
}
Arrays.copyOf 源码
源码原始注释英文翻译 复制指定的数组、截断或使用空值填充(如有需要) 所以拷贝有指定的长度。对于所有的指标
在原始数组和副本中都有效,这两个数组将 包含相同的值。中的任何有效的索引 复制但不是原始的,复制将包含{@code null}。
当且仅当指定长度时,这些索引才存在 大于原始数组的值。 生成的数组与原始数组的类完全相同。
/**
* Copies the specified array, truncating or padding with nulls (if necessary)
* so the copy has the specified length. For all indices that are
* valid in both the original array and the copy, the two arrays will
* contain identical values. For any indices that are valid in the
* copy but not the original, the copy will contain {@code null}.
* Such indices will exist if and only if the specified length
* is greater than that of the original array.
* The resulting array is of exactly the same class as the original array.
*
* @param <T> the class of the objects in the array
* @param original the array to be copied
* @param newLength the length of the copy to be returned
* @return a copy of the original array, truncated or padded with nulls
* to obtain the specified length
* @throws NegativeArraySizeException if {@code newLength} is negative
* @throws NullPointerException if {@code original} is null
* @since 1.6
*/
@SuppressWarnings("unchecked")
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by 50% if that suffices.
* Will not return a capacity greater than MAX_ARRAY_SIZE unless
* the given minimum capacity is greater than MAX_ARRAY_SIZE.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
// 返回扩容新数组的长度
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 声明一个新的变量 大小为 elementData.length 长度的 1.5 倍
// oldCapacity >> 1 oldCapacity 右移一位,其效果相当于oldCapacity /2
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 判断新的扩容长度是否超过,
if (newCapacity - minCapacity <= 0) {
// elementData 存储ArrayList元素的数组缓冲区
// DEFAULTCAPACITY_EMPTY_ELEMENTDATA 用于默认大小的空实例的共享空数组实例
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// 返回 DEFAULT_CAPACITY minCapacity 其中的最大值
// DEFAULT_CAPACITY 默认10
return Math.max(DEFAULT_CAPACITY, minCapacity);
// 传入的长度小于0时,抛出异常
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// 返回 原容量+新增的元素的个数
return minCapacity;
}
// MAX_ARRAY_SIZE 要分配的数组的最大大小(除非必要)
// 判断 newCapacity 扩容的新的数组长度是否 超过最大范围
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
// 判断 minCapacity 为负数 抛出异常OutOfMemoryError
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// minCapacity
//MAX_ARRAY_SIZE 要分配的数组的最大大小(除非必要)
//如果要分配的大小超过MAX_ARRAY_SIZE 就使用Integer的最大大小
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
/**
* The maximum size of array to allocate (unless necessary).
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
整理总结:
每次ArrayList扩容,默认自动扩容多大
分为多种情况
1、 return Math.max(DEFAULT_CAPACITY, minCapacity);
DEFAULT_CAPACITY(值是10),说明:如果通过new ArrayList()来生成,第一次扩容默认采用
2、return (newCapacity - MAX_ARRAY_SIZE <= 0)? newCapacity : hugeCapacity(minCapacity);
原容量的一半:oldCapacity + (oldCapacity >>1),说明:默认扩容的容量是原容量的一半newCapacity,条件是newCapacity比minCapacity大且小于最大容量的定
3、return minCapacity; // 返回 原容量+新增的元素的个数
原容量+新增的元素的个数,说明:默认扩容的容量是原容量的一半newCapacity,但是如果newCapacity比minCapacity小,再扩容的大小为minCapacity
4、 return (minCapacity > MAX_ARRAY_SIZE)?Integer.MAX_VALUE : MAX_ARRAY_SIZE;
Integer.MAX_VALUE,说明:minCapacity> Integer.MAX_VALUE - 8,则扩容的大小是Integer.MAX_VALUE
5、MAX_ARRAY_SIZE Integer.MAX_VALUE - 8