ArrayList无参构造添加元素源码解读
一、ArrayList无参构造add方法源码阅读
@Test//无参构造源码阅读
public void testArrayListNoConstructorAdd(){ArrayList<Integer> arrayList = new ArrayList<>();ArrayList<Integer> list = new ArrayList<>();arrayList.add(1);arrayList.add(12);arrayList.add(13);
}
就用这个为测试吧。
对于arrayList.add(1)
debug进去:
看到进来了这里:
1、来到Integer类方法内部
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}
对于IntegerCache.cache[i + (-IntegerCache.low)];
这里应该是将cache索引为i - IntegerCache.low的元素返回,对于cache这个数组存储的个数是2x128 = 28
也就是可以存储[-128,127]这些元素。
不信可以借助工具查看:
发现确实是这样。
2、来到ArrayList的add方法:
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;
}
size是什么?查看一下:
/*** The size of the ArrayList (the number of elements it contains).** @serial*/
private int size;
确实是大小,实锤了!!!
3、来到ensureCapacityInternal
private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//elementData是Object[0]@1098,不知道是什么,minCapacity是1
}
4、来到calculateCapacity:
private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//defaultcapacity_empty_elementdata这里是true的。return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY=10/**DEFAULT_CAPACITY: Default initial capacity.private static final int DEFAULT_CAPACITY = 10;*/}return minCapacity;
}
返回到:
ensureExplicitCapacity - > "Explicit是明确的意思"
来到:
private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);
}
minCapacity >elementData.length成立:
private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}
来到Arrays.copyof:
这里的original是一个对象吧
看到上一步是:
//类成员:transient Object[] elementData;
也就是elementData这个玩意,忍了很久了,之前一度怀疑这个是不是存储节点的数据,看看它的介绍发现果然是:
* The array buffer into which the elements of the ArrayList are stored.* The capacity of the ArrayList is the length of this array buffer. Any* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* will be expanded to DEFAULT_CAPACITY when the first element is added.翻译下:* 存储 ArrayList 元素的数组缓冲区。* 数组列表的容量是此数组缓冲区的长度。任何* 空的数组列表与元素数据 == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* 将在添加第一个元素时扩展到 DEFAULT_CAPACITY。
那么就继续copyof这个方法:
public static <T> T[] copyOf(T[] original, int newLength) {return (T[]) copyOf(original, newLength, original.getClass());
}
首先,分析一下这个类,返回的是一个T泛型类,那么也就是和elementData同一个类型的对象。
来到:
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {@SuppressWarnings("unchecked")T[] copy = ((Object)newType == (Object)Object[].class)? (T[]) new Object[newLength]: (T[]) Array.newInstance(newType.getComponentType(), newLength);System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));return copy;
}
应该是走(Object)newType == (Object)Object[].class
是true,于是走这边(T[]) new Object[newLength]
了,然后再来到:
System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));
这里很明显是将original的这里的内容拷贝到新的对象copy这个对象里了
,然后再返回新对象给:
public static <T> T[] copyOf(T[] original, int newLength) {
再回到:
private void grow(int minCapacity) {
返回copy给elementData.
再回到ArrayList的这个方法把里面的grow方法执行完再结束:
private void ensureExplicitCapacity(int minCapacity) {
结束。
再回到:
private void ensureCapacityInternal(int minCapacity) {
再回到add方法将最后2行执行完就结束:
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;
}
二、回顾:
第一步先去确认下容器大小怎么样。
如果是第一次add,就给10个容量。人哈就去扩容也就是grow方法。
这里的grow是怎么扩容呢?
看看源码:
private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)//如果比MAX_ARRAY_SIZE这个都大,那么就去newCapacity = hugeCapacity(minCapacity);//获取更大的容量// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}
这里就是先按照增加原来的一半容量吧。从int newCapacity = oldCapacity + (oldCapacity >> 1)
可以看出。>>
这个符号就是有符号右移嘛,也就是除以2。
总结一下:
对于无参构造创建的ArrayList,一开始容器大小也就是size = 0,当要添加元素时,便是第一次添加元素,会扩容10个大小。后面继续添加元素时每次都会和之前的容量大小比较一下,刚好不够了再扩容,扩大50%。
先做数据的迁移,再做数据的添加。
如果是第二次扩容1,那么就是添加第11个元素时,先去grow一下,新创建数组大小为15的copy(也就是扩容),然后迁移数据。然后再将copy返回给elementData,再进行add,将元素添加到已经扩容了的elementData的末尾,可以使用这个来查看一下:
@Test//无参构造源码阅读
public void testArrayListNoConstructorAdd(){ArrayList<Integer> arrayList = new ArrayList<>();ArrayList<Integer> list = new ArrayList<>();for (int i = 0; i <20; i++) {arrayList.add(i);}
}
过程和本文讲解的是一样的。
end