ArrayList作为一个新手最常用的集合,一直都没有研究他内部的实现,既然下定决心要写博客,就不管什么大小事都记录一下吧,或许真的有用呢?
首先ArrayList有三个构造函数(jdk8)
1. new ArrayList();
2. new ArrayList(int initialCapacity);
3. new ArrayList(Collection<? extends E> c);
由于ArrayList的内部就是一个数组,所以它的构造函数都是对Object[] elementData进行初始化
下面看看ArrayList是如何实现增删的
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1);
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null;
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;
}
}
return false;
}
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;
}
1. 总体来说add方法都是先检查数组大小是否需要扩容,再赋值。由于ArrayList是非线程安全,在多线线程的情况下,请勿使用,例如2个线程同时对一个数组插入数据,当size==9时,2个线程同时通过了ensureCapacityInternal检查的情况下,就会出现java.lang.ArrayIndexOutOfBoundsException
2. 每次删除都需要用System.arraycopy对数组进行复制,例如arr[1,2,3,4],若把arr[1]删除,就要把arr[2]后面的内容,复制到原来的位置上,由于不是java的方法不能进入内部查看。
3. 这样就清楚ArrayList增删没有LinkedList快的原因了。