Arraylist原理及源码分析
闲话
以前学习从来不看源码 ,一是怕麻烦,二是看不懂,到现在这些简单问题还是不清楚,只能被面试官吊打了,今天就拿Arralist先开刀。
一、ArrayList的数据结构
ArrayList的底层数据结构就是一个数组,数组元素的类型为Object类型,对ArrayList的所有操作底层都是基于数组的。

二、ArrayList的线程安全性
对ArrayList进行添加元素的操作的时候是分两个步骤进行的,即第一步先在object[size]的位置上存放需要添加的元素;第二步将size的值增加1。由于这个过程在多线程的环境下是不能保证具有原子性的,因此ArrayList在多线程的环境下是线程不安全的。
具体举例说明:在单线程运行的情况下,如果Size = 0,添加一个元素后,此元素在位置 0,而且Size=1;而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增 加 Size 的值。 那好,现在我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而Size却等于 2。这就是“线程不安全”了。
如果非要在多线程的环境下使用ArrayList,就需要保证它的线程安全性,通常有两种解决办法:第一,使用synchronized关键字;第二,可以用Collections类中的静态方法synchronizedList();对ArrayList进行调用即可。
三、ArrayList的继承关系
ArrayList继承AbstractList抽象父类,实现了List接口(规定了List的操作规范)、RandomAccess(可随机访问)、Cloneable(可拷贝)、Serializable(可序列化)。

四、源码分析
1. 属性分析
//显示指定序列化id 之前解释过
private static final long serialVersionUID = 8683452581122892189L;
//初始默认容量为10
private static final int DEFAULT_CAPACITY = 10;
// 如果构造方法传入的capacity=0 就会返回这个 下面构造方法可以看到
private static final Object[] EMPTY_ELEMENTDATA = {};
//空参默认是这个
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//Object数组
transient Object[] elementData; // non-private to simplify nested class access
//数组长度
private int size;
//数组最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
2. 构造方法分析
三个构造方法 ,如下:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//就创建容量为initialCapacity数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//返回EMPTY_ELEMENTDATA
this.elementData = EMPTY_ELEMENTDATA;
} else {
//长度不合法异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList() {
//返回EMPTY_ELEMENTDATA
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//传入一个collection参数
public ArrayList(Collection<? extends E> c) {
//把传入的集合转化成数组并赋给elementData
elementData = c.toArray();
//如果长度不为0
if ((size = elementData.length) != 0) {
//如果elementData类型不是Object
if (elementData.getClass() != Object[].class)
//把elementData数组改拷贝为Objectp[]
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//空数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
3. 主要方法
// 1)把容量减到实际长度
public void trimToSize() {
//修改次数增加
modCount++;
//如果列表长度小于容量
if (size < elementData.length) {
elementData = (size == 0)
//{}
? EMPTY_ELEMENTDATA
//长度缩减至size实际容量
: Arrays.copyOf(elementData, size);
}
}
// 2)检查容量
public void ensureCapacity(int minCapacity) {
//传入的minCapacity大于数组容量 并且数组不为{} ,minCapacity大于默认容量
if (minCapacity > elementData.length
&& !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
&& minCapacity <= DEFAULT_CAPACITY)) {
modCount++;
//扩容
grow(minCapacity);
}
}
// 3)扩容方法
private Object[] grow(int minCapacity) {
//原数组拷贝到新数组 新数组容量调用newCapacity方法
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
//旧长度
int oldCapacity = elementData.length;
//旧长度+旧长度右移1位 即为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新长度小于等于minCapacity
if (newCapacity - minCapacity <= 0) {
//如果数组为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
//返回他两中的最大值
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
//小于 MAX_ARRAY_SIZE 返回newCapacity 否则调用hugeCapacity返回最大值
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
// 4)获取元素方法
public E get(int index) {
//检查是否越界
rangeCheck(index);
return elementData(index);
}
//检查是否越界
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 5)添加元素方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//指定下标添加
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++;
}
// 6)删除元素
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;
}

浙公网安备 33010602011771号