首先看一下他的构造函数:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
其实arraylist还有其他的构造函数,可以指定数组的长度,这里先从最基本的入手
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
这个DEFAULTCAPACITY_EMPTY_ELEMENTDATA 其实就是一个空的数组,在这里的作用就是为了表示这是一个空的的数组
而elementData 是arraylist真正用来存放数据的地方
那么可以注意到,初始话完成以后,整个数组的长度就是0,arraylist 正在开始让他有长度,是在add操作的时候完成的,下面去看下add操作
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
总共两端代码 后一段好理解,就是给数组赋值,然后把代表数组长度的size+1
我们进入ensureCapacityInternal 去看看。注意他的参数,是当前数组的长度+1
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
从参数名minCapacity 的字面意思我们就能知道,意思是最小的容量,
之后先判断数组是不是一个空数组 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
如果是,我们看下当前需要的最小容量和DEFAULT_CAPACITY
谁更加大,这个DEFAULT_CAPACITY
是arraylist 的一个常量是10,所以看到这里我们已经知道arraylist默认的长度是10。
好了这里取最大的值,所以我们的`minCapacity
变成了10
我们继续看下一个函数ensureExplicitCapacity
先看字面意思是明确的确保容量,看来arraylist很谨慎
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
首先会注意到这里有一个modCount,他其实和现在我们分析的没关系,这是一个用来记录操作次数的东西,你增加删除读取都会记录,主要用在线程安全上
然后是minCapacity - elementData.length > 0
其实就是比较大小,如果当前需要的空间minCapacity 大于elementData 能提供的空间,我们就需要扩容,也就是grow操作
否则就完事了,我们知道现在elementData的长度为0,那肯定要扩容了,进入grow看看
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//拿出现在数组的长度
//扩容,扩容方式就是原来的长度+原来长度的一半,也就是右移一位
int newCapacity = oldCapacity + (oldCapacity >> 1);
//就我们分析的情况 扩容后的长度是0+0/2还是0
//这里就看下扩容后的长度能不能满足最小需要的长度,现在看来是不能的那就用最小需要的长度代替扩容的长度吧
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:
//扩容,现在我们的数组长度为10啦
elementData = Arrays.copyOf(elementData, newCapacity);
}
初始化分析到这里就结束了,后面看几个常用的操作
get set remove 其实真的大同小异
先看get
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
这里涉及到第一个函数rangeCheck
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
他做了一个判断,当前请求的位置是不是在数组的长度范围内,不是抛出异常,是的话啥事没有
然后是elementData
E elementData(int index) {
return (E) elementData[index];
}
这个就没什么好讲了就是把数组指定位置取出来返回,但请牢记这个函数,后面都会用到他
现在看remove
public E remove(int index) {
//越界检查
rangeCheck(index);
//操作记录
modCount++;
//拿到这个要删除的点
E oldValue = elementData(index);
int numMoved = size - index - 1;
//这里的操作就是把要删除位置后面的数据都向前一定一位
//System.arraycopy(要操作的数组,开始操作的位置,目标数组,目标数组开始的位置,复制的长度)
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
最后看set
public E set(int index, E element) {
//越界检查
rangeCheck(index);
//拿到旧值
E oldValue = elementData(index);
//赋新的值
elementData[index] = element;
//返回旧值
return oldValue;
}
最后我们看一下迭代器部分的代码
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
//我们看到arraylist开始使用哪个奇怪的一直在计数的变量的,先把他复制一份
int expectedModCount = modCount;
//判断还有没有下一个
public boolean hasNext() {
//看当前阅读的指针有没有超出总长度
return cursor != size;
}
@SuppressWarnings("unchecked")
//这是访问下一个
public E next() {
//检查
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
//到下一个节点
cursor = i + 1;
//返回当前遍历节点的数据
return (E) elementData[lastRet = i];
}
//删除节点
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
//如果两个值不相等,说明在我们便利的时候有线程动了这个arraylist ,这里抛出异常快速失败!
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
总结一下arraylist 底层是数组,默认长度是10,可以自主扩展,扩展的长度是
原数组的长度+原数组长度/2 也就是新的数组是原来的1.5倍