1.常量数据
/**
* 默认容量大小
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 默认空数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存放数据元素的数组
*/
transient Object[] elementData; // non-private to simplify nested class access
2.构造器
/**
* 带初始化容量的构造器
*/
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);
}
}
/**
* 不带初始化容量的构造器(在初始化的时候并没有指定大小,而是给了一个空数组
,只有在第一次add的时候才会扩容为10,详细见下面的扩容分析)
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 初始化的时候就赋值构造器
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
3.扩容机制分析
/**
* 要分配的最大数组大小
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
/**
* 用于处理没有指定容量就初始化的情况,当没有指定容量初始化的时候就会在这里给一个默认大小10
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
/**
* 判断是否需要扩容
* minCapacity:需要的容量大小
*/
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 如果需要的容量比当前数组的长度要长,这时就需要进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 扩容的核心方法
*/
private void grow(int minCapacity) {
// 得到当前数组的长度
int oldCapacity = elementData.length;
// 按照1.5倍左右进行扩容,如果oldCapacity是偶数则是1.5倍,否则是1.5左右
// >> 1 相当于除2,此位运算相当于除以2的幂次方,这里为什么不用算术运算,
// 因为位运算的性能要比算术运算好很多,只需要移动位置即可
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩容以后的长度还是比所需要的长度小,就将所需要的长度给扩容的长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;、
// 如果扩容以后的长度大于分配数组的最大长度,防止造成内存泄露,将最大容量设置Integer.MAX_VALUE或者为MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 根据扩容长度进行扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
4.add方法
/**
* 添加元素
*/
public boolean add(E e) {
// 判断是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将元素放入数组中
elementData[size++] = e;
return true;
}
通过上面我们可以知道,当没有指定初始化容量实例化对象的时候,首先会给一个空数组,只有在add第一个元素的时候才会扩容为10,现在来看一下整个流程
1.当添加第一个元素的时候,进入到calculateCapacity方法的以后,此时会返回DEFAULT_CAPACITY
2.紧接着进入到ensureExplicitCapacity中,判读成立,进行扩容
3.当第二个元素进去的时候,minCapacity为2,再次进入到ensureExplicitCapacity时,2-10 > 0 不成立,所以不会进行扩容
4.直到第11个元素进去的时候,此时minCapacity为11,再次进入到ensureExplicitCapacity的时候11-10成立,进行扩容,扩容得到的新值为10 + 10/2 = 15。
5.注意事项
1.为什么明明默认初始化是10,还要在初始化的时候去指定长度呢?
因为默认初始化的时候只会指定为空数组,并不会指定容量的大小,只有在第一个元素进去的时候才会进行扩容,而直接指定初始化大小,就不需要做哪些扩容操作,性能肯定是更好的。