您的位置:首页 > 编程语言 > Java开发

java ArrayList源码分析

2018-03-12 22:08 573 查看
继承了AbstractList抽象类(该类继承了AbstractCollection和List接口)实现了List, RandomAccess, Cloneable, java.io.Serializable接口。

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable


序列化ID:

private static final long serialVersionUID = 8683452581122892189L;


默认容量为10:

private static final int DEFAULT_CAPACITY = 10;


底层是数组:

//空的对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//空的对象数组和上面的区别在于当添加第一个元素时知道扩充多少容量
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//相当于是个缓冲区,任何空的ArrayList满足elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA时会被扩充成默认容量(10)在第一个元素被添加的时候。
transient Object[] elementData;//transient 代表该类在序列化时阻止该变量持久化


三个构造函数:分别是带容量的参数,无参,和带Collection参数的构造函数。

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);
}
}

//构造容量是10的ArrayList
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

//按collection 的 iterator传入
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;
}
}


给ArrayList瘦身,且和size一样大(size是已经使用的容量)。用Arrays.copyOf复制了已经使用的那部分组成一个新的数组相当于把尾巴多出的容量给剪掉了。

public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}


扩容:可以看到默认扩充newCapacity是oldCapacity的1.5倍,如果传入了参数miniCapacity就会当成新的扩充容量,这里还考虑了整型上限问题,最多只能扩充到0x7fffffff。

//一些VM会占用头部字节,这里规定了最大上限,超过就会抛出OutOfMemoryError异常
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
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);
}


在执行add()方法时,我们看到会调用这样一条方法
ensureCapacityInternal(size + 1);
这个方法会将一个继承自AbastractList的mod变量自增1,该变量用来记录list长度被修改的次数在遍历时根据情况抛出异常;同时该方法会对ArrayList进行扩容,容量+1。

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++;
}

private void ensureCapacityInternal(int minCapacity)
b61f
{
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}

ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
modCount++;

// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}


同样addAll()也类似,扩容的容量取决于加入集合的长度:

public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew);  // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}


在执行add()或者remove()方法时,我们能看到底层调用的还是
void System.arraycopy(Object src, int  srcPos,Object dest, int destPos,int length);
这个方法。对于数组如果删除的是中间的元素,那么后面的元素都要往前挪,同样的,增加中间的元素,后面的元素都要往后挪。

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; // clear to let GC do its work

return oldValue;
}


在这里通过调用clear()我们可以看到底层只是通过将元素置空,等待GC自动回收。

public void clear() {
modCount++;

// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;

size = 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: