ArrayList
List接口的主要实现类
线程不安全,随机访问元素快,效率高;底层使用Object[] elementDate数组。
源码分析
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
调用无参构造函数时,默认创建长度为10的数组elementDate存储Object类型的数据
list.add(元素1); //elementData[0] = new Object(元素);
...
...
list.add(元素n); //如果此次的添加导致底层elementData数组容量不够,则扩容
扩容机制:
private void grow(int minCapacity) {
// overflow-conscious code
int 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);
}
// 扩容:10(调用无参构造时默认的大小),15,22,33,...
默认情况下,当数组长度不够时扩容到原长度的1.5倍,同时将原有数组中的数据复制到新的数组中。当扩容达到最大值时仍需要扩容,则抛异常,最大值为Integer.MAX_VALUE - 8。
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
然而下列源码颠覆我的认知,让我有点懵:
private void grow(int minCapacity) {
// overflow-conscious code
int 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:
// minCapacity的大小 通常接近size的大小,所以下列代码执行:
elementData = Arrays.copyOf(elementData, newCapacity);
}
// 当minCapacity 小于0时,内存溢出;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
并且,在调用构造函数创建ArrayList对象时,传入一个Integer.MAX_VALUE是会出现错误的java.lang.OutOfMemoryError: Requested array size exceeds VM limit
;只有当传入参数为Integer.MAX_VALUE - 2以及减去更大的值时才是java.lang.OutOfMemoryError: Java heap space
内存限制。Integer.MAX_VALUE - 2是我的虚拟机限制数组大小的临界值。
创建ArrayList时,在知道数据多少的情况下,推荐使用带参构造函数,避免数组长度不够时进行的扩容行为。
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);
}
}
当初始长度大于0时,创建数组,长度为initialCapacity = 10;
当初始长度为0时,创建数组,长度为EMPTY_ELEMENTDATA;
否则抛出IllegalArgumentException异常。
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
构造一个包含指定collection的元素的列表,这些元素是按照该collection的迭代器返回她们的顺序排列的。
将collection对象传入,并将其转换为名为elementData的数组
当数组长度不为0,且数组的类型与Object[]数组的类型不同时, 复制elementData数组,截取或用 null 填充(如有必要),以使副本具有指定的长度;
当数组长度等于0时,创建一个名为elementData的数组,其长度为EMPTY_ELEMENTDATA的长度。