简介:
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
ArrayList 继承了 AbstractList ,并实现了 List 接口。
属性:
成员变量:
transient Object[] elementData; //集合底层数据操作的数组
private int size; //集合的长度
protected transient int modCount = 0;//修改的次数(父类的成员变量)
常量:
private static final int DEFAULT_CAPACITY = 10;//集合的默认长度
private static final Object[] EMPTY_ELEMENTDATA = {};//空数组,一般赋值使用
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//空数组
构造器:
public ArrayList():
将空数组复制个elementData,创建一个空集合,因此调用无参构造方法默认创建一个不占用内存空间的集合。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity):
创建一个initialCapacity大小内存空间的集合,initialCapacity必须大于或等于0。
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);
}
}
public ArrayList(Collection<? extends E> c):
将集合转换为数组。判断数组的长度是否大于0,如果大于0则判断参数c的类型是否为ArrayList,如果是直接赋值给elementData,如果不是则进行拷贝。底层用的是System.arraycopy。如果长度等于0则直接将空数组EMPTY_ELEMENTDATA赋值给elementData。
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
方法:
add(E e):
调用add(e, elementData, size)。
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
add(E e, Object[] elementData, int s):重点
将元素添加到size索引空间内。(并不是集合最后一个元素, 因为size并不是elementData最后一个元素的索引)
源码中,数组扩充有五种情况:
elementData.length > 0: 将elementData的长度扩充为10,并且将添加的值存入到索引0的空间内;
elementData.length <= 10: 直接将数据添加到elementData中;
elementData.length > 10:将elementData的长度扩大到1.5倍,如果扩充的长度还是小于最小容量minCapacity,直接将elementData的数据扩容到minCapacity长度,并且将原数据拷贝到elementData中;
elementData.length > MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8) : 将elementData的数组长度扩容到Integer.MAX_VALUE,并且将源数据拷贝到elementData中;
elementData.length > Integer.MAX_VALUE : 报错;
总结:一个空集合第一次扩充的容量为10,当需要的容量大于10之后就是每次扩容当前集合底层数组长度的1.5倍,如果扩容的长度小于需要的长度,则直接扩容到需要的长度。集合最大长度为Integer.MAX_VALUE。
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();//扩充ArrayList数组
elementData[s] = e;
size = s + 1;
}
添加一个元素调用的所有方法:
private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
//集合达到极限的处理
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
add(int index, E element):
将存储数据的数组进行扩容将元素添加到index索引的内存空间内,并且将index索引后面的所有元素拷贝到 index+1,index+2......索引空间内。
public void add(int index, E element) {
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
//拷贝 其他的就是数组扩容 可以看上方解析
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
public E remove(int index):
首先判断要删除的索引是否越界。然后将index索引后面的值都赋值给前面,最后一个索引的值赋值为null。类似于 elementData[index] = elementData[index + 1];elementData[index + 1] = elementData[index + 2];.....最后elementData[--size] = null。
public E remove(int index) {
Objects.checkIndex(index, size);
final Object[] es = elementData;
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
boolean remove(Object o):
删除集合中第一个o元素。底层就是一个for循环遍历数组elementData,如果找到了则结束for循环,如果没找到则返回false。找到索引之后也是运行的fastRemove(Object[] es, int i)方法。
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
return false;
}
fastRemove(es, i);
return true;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}