ArrayList源码分析
1.构造方法
传一个int型的构造方法:根据传入的参数大于0,创建一个长度为参数的数组并且赋值给elementData这个成员变量,如果参数等于0,赋值为一个空的数组,否则,报错。所以,这也印证了,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); }
}
空参构造方法:它执行的操作是给成员变量elementData赋值一个默认的容量,而这个容量是一个private,static,final类型的空数组,即private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
传一个集合类型的参数:将传入的集合转为数组赋值给成员变量,然后判断它的长度是否为0,如果不为0,进而判断它是否为Object类型的数组,如果不是的话,给它copyOf()为一个Object类型的数组。否则,给它置空。
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;
}
}
2.插入数据:add()方法
在末尾添加元素:首先要判断是否需要扩容,ensureCapacityInternal(size + 1),size+1传入为最小容量,modCount++,调用grow()扩容
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
在指定位置添加元素:首先rangeCheckForAdd(index)判断索引是否超出数组下标,之后检测是否需要扩容,System.arraycopy()除去指定位置,把指定位置的以后的元素向后移一位,将index位置赋新值
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1,size - index);
elementData[index] = element;
size;
}
3.扩容
扩容的时候首先会调用的方法,计算容量,minCapacity即上述的size+1
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
计算最小容量,DEFAULTCAPACITY_EMPTY_ELEMENTDATA(默认容量)是10,
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity); }
return minCapacity;
}
传入最小容量,首先修改+1,minCapacity - elementData.length > 0判断你需要的容量与默认容量的大小,差为负值是不需要扩容的。
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
数组扩容:首先把数组的长度赋给老的容量,也就是10,然后新的容量newCapacity=老的容量(10)+老的容量右移一位(5),如果新容量-(size+1)为负数,把size+1赋给新容量。如果新容量比数组的最大扩容量都大,会报异常,或者把最大的赋给它。如果都不是,就把新容量拷贝给数组,扩容完成。
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);
}
4.删除
指定位置删除:首先检测是否越界,然后修改+1,
public E remove(int index) {
rangeCheck(index);
modCount++;
//返回要删除的元素
E oldValue = elementData(index);
//将index+1以及之后的元素向前移动一位,覆盖被删除的值
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,numMoved);
//将最后一个位置的元素清空
elementData[--size] = null; // clear to let GC do its work return oldValue;
}
指定元素删除:首先判断是否为空,空的时候直接删除
public boolean remove(Object o) {
//判断元素是否为空
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
//如果没有匹配元素,返回false
return false;
}
快速删除:不需要检测index,直接删除
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,numMoved); elementData[--size] = null; // clear to let GC do its work
}
5.遍历,删除异常及解决办法
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
如果for直接调用remove()方法会报错,因为modCount首先会+1,而expectedModCount是一开始遍历产生的
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
但如果用迭代器遍历然后在删除就不会报错,因为expectedModCount = ArrayList.this.modCount;重新赋值了
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
SubList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}