ArrayList集合
1. 方法
public class ArrayList<E> extends AbstractList<E>
implements List<E>
ArrayList继承了Collection类,且接口为List,所以父类和接口中的方法都可以使用
2. 底层原理
ArrayList底层是数组结构的
结论
- 利用空参创建的集合,在底层创建了一个默认长度为0的数组
- 添加第一个元素时,底层会将数组的长度扩充为一个新的长度——10
- 存满时,会扩容1.5倍
- 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准
2.1 空参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//跳转到elementData
transient Object[] elementData;
//再跳转到DEFAULTCAPACITY_EMPTY_ELEMENTDATA中
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
- 从空参构造的底层代码可以看出ArrayList为数组,而elementData为数组的名称,而其长度为0,(DEFAULTCAPACITY_EMPTY_ELEMENTDATA 长度为0)
2.2 扩容的底层原理
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
The size of the ArrayList (the number of elements it contains).
@serialsize:数组列表的大小(它包含的元素数)
- 第一次中调用add(E e)时,系统会再调用另一种的add(e, elementData,size)进行数据添加,其中e为我们要储存的元素,elementData为我们在调用空参构造时,系统自动构造的空数组,size为数组中的元素个数和集合的长度(不等同element.length,即数组长度)
- 分析第二次add方法,当s == elementData.lengt时,elementData = grow()进行跳转;第四步中elementData.length增大到10,即s不等于elementData.length,elementData[ ] = e 进行数据存储,并且size也相应+1,当存储了10个元素时(即size == 10),s == elementData时,加入grow()方法,直接跳转到第五步
//这里跳转到了grow()方法
private Object[] grow() {
return grow(size + 1);
}
- grow()方法中又调用了一次grow()方法,而传入实参为 size + 1
//再次跳转到grow()
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
private static final int DEFAULT_CAPACITY = 10;
- 在grow(int minCapacity)中,minCapacity = size + 1
- 第二行中,变量oldCapacity储存原来的elementData数组的长度
- 第一次时,oldCapacity = 0,minCapacity = 1,且elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA,所以不符合if判断,进入else中,DEFAULT_CAPACITY > minCapacity,则elementData的长度增大到10,这时再返回第二步中进行数据储存
- 当size == 10时,minCapacity == 11,oldCapacity = 10,符合if()判断,调用ArraysSupport.newLength(int oldLength, int minGrowth, int prefGrowth)方法,其中int oldLength的实参为oldCapacity,int minGrowth的实参为minCapacity - oldCapacity,int prefGrowth的实参为oldCapacity >> 1(等同于oldCapacity/2)
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
// preconditions not checked because of inlining
// assert oldLength >= 0
// assert minGrowth > 0
int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
return prefLength;
} else {
// put code cold in a separate method
return hugeLength(oldLength, minGrowth);
}
}
public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;//2147483639
@Native public static final int MAX_VALUE = 0x7fffffff;//2147483647
- oldLength = 10,minGrowth =1,prefGrowth = 5. 则prefLength = 15,进行if判断,return preLength == 15,则在第五步中 newCapacity = preLength = 15,然后return elementData,这里又调用了Arrays.copyOf(T[] original,int newLength)方法,T[] original的实参为 elementData, int newLength的实参为 newCapacity
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
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;
}
- 用copyof()方法进行复制,创建一个长度为newCapacity = 15的新数组,并把elementData的数据复制到新数组,在把新数组赋值给elementData。