ArrayList
总结
(1)ArrayList内部使用数组存储元素,当数组长度不够时进行扩容,每次加一半的空间,ArrayList不会进行缩容;
(2)ArrayList支持随机访问,通过索引访问元素极快,时间复杂度为O(1);
(3)ArrayList添加元素到尾部极快,平均时间复杂度为O(1);
(4)ArrayList添加元素到中间比较慢,因为要搬移元素,平均时间复杂度为O(n);
(5)ArrayList从尾部删除元素极快,时间复杂度为O(1);
(6)ArrayList从中间删除元素比较慢,因为要搬移元素,平均时间复杂度为O(n);
(7)ArrayList支持求并集,调用addAll(Collection c)方法即可;
(8)ArrayList支持求交集,调用retainAll(Collection c)方法即可;
(7)ArrayList支持求单向差集,调用removeAll(Collection c)方法即可;
构造函数:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else {
if (initialCapacity != 0) { //传入初始容量小于零时
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
this.elementData = EMPTY_ELEMENTDATA; // 等于零时,空对象数组
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //如果没有传入初始容量,则使用空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA
}
// 把传入集合的元素初始化到ArrayList中
public ArrayList(Collection<? extends E> c) {
this.elementData = c.toArray(); // 集合转数组
if ((this.size = this.elementData.length) != 0) {
// 检查c.toArray()返回的是不是Object[]类型,如果不是,重新拷贝成Object[].class类型
if (this.elementData.getClass() != Object[].class) {
this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class);
}
} else {
this.elementData = EMPTY_ELEMENTDATA; // // 如果c的空集合,则初始化为空数组EMPTY_ELEMENTDATA
}
}
add(E e)方法
添加元素到末尾,平均时间复杂度为O(1)。
public boolean add(E e) {
++this.modCount;
this.add(e, this.elementData, this.size);
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length) {
elementData = this.grow(); //扩容
}
elementData[s] = e;
this.size = s + 1;
}
private Object[] grow() {
return this.grow(this.size + 1);
}
private Object[] grow(int minCapacity) {
// 创建新容量的数组并把老数组拷贝到新数组
return this.elementData = Arrays.copyOf(this.elementData, this.newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
int oldCapacity = this.elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //1.5倍扩容
if (newCapacity - minCapacity <= 0) {
if (this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(10, minCapacity); // 初始10,或用于addAll中,用来选择相符合的容量
} else if (minCapacity < 0) {
throw new OutOfMemoryError();
} else {
return minCapacity;
}
} else {
return newCapacity - 2147483639 <= 0 ? newCapacity : hugeCapacity(minCapacity);
}
}
add(int index, E element)方法
添加元素到指定位置,平均时间复杂度为O(n)。
public void add(int index, E element) {
// 检查是否越界
this.rangeCheckForAdd(index);
++this.modCount;
int s;
Object[] elementData;
if ((s = this.size) == (elementData = this.elementData).length) {
elementData = this.grow(); // 扩容
}
// 把插入索引位置后的元素都往后挪一位,在插入索引位置放置插入的元素;
System.arraycopy(elementData, index, elementData, index + 1, s - index);
elementData[index] = element;
this.size = s + 1;
}
addAll(Collection c)方法
求两个集合的并集
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
++this.modCount;
int numNew = a.length;
if (numNew == 0) {
return false;
} else {
Object[] elementData;
int s;
if (numNew > (elementData = this.elementData).length - (s = this.size)) {
elementData = this.grow(s + numNew);
}
// 把数组a中的元素拷贝到elementData的尾部;
System.arraycopy(a, 0, elementData, s, numNew);
this.size = s + numNew;
return true;
}
}
remove(int index)方法
删除指定索引位置的元素,时间复杂度为O(n)。
如果删除的不是最后一位,则其它元素往前移一位;将最后一位置为null,方便GC回收;
可以看到,ArrayList删除元素的时候并没有缩容。
public E remove(int index) {
Objects.checkIndex(index, this.size);
Object[] es = this.elementData;
E oldValue = es[index];
this.fastRemove(es, index);
return oldValue;
}
private void fastRemove(Object[] es, int i) {
++this.modCount;
int newSize;
if ((newSize = this.size - 1) > i) {
System.arraycopy(es, i + 1, es, i, newSize - i);
}
es[this.size = newSize] = null;
}
remove(Object o)方法
删除指定元素值的元素,时间复杂度为O(n)。
找到第一个等于指定元素值的元素;快速删除;
fastRemove(int index)相对于remove(int index)少了检查索引越界的操作,可见jdk将性能优化到极致。
public boolean remove(Object o) {
Object[] es = this.elementData;
int size = this.size;
int i = 0;
if (o == null) {
while(true) {
if (i >= size) {
return false;
}
if (es[i] == null) {
break;
}
++i;
}
} else {
while(true) {
if (i >= size) {
return false;
}
if (o.equals(es[i])) {
break;
}
++i;
}
}
this.fastRemove(es, i);
return true;
}