ArrayList源码分析
1. 基础了解
1.1 四个关注点
是否允许空 | 允许 |
---|---|
是否允许重复值 | 允许 |
是否有序 | 有序 |
是否线程安全 | 线程不安全 |
1.2 成员变量
transient Object[] elementData | 底层object数组实现 |
---|---|
private int size | 保存当前数组的元素个数(不是数组长度) |
DEFAULT_CAPACITY = 10; | 默认初始容量(空构造时会使用) |
Object[] EMPTY_ELEMENTDATA = {}; | 有参构造时使用(传入的参数是0时使用) |
Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; | 空构造时赋值给elementData |
int MAX_ARRAY_SIZE | 数组最大容量:Integer.MAX_VALUE - 8; |
2. ArrayList对象的创建
2.1 空构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2.2 带参构造
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);
}
}
2.3 有参构造
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();//转成数组时可能不是object数组,所以后面复制时要复制成object数组
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;
}
}
3. 常使用的方法
3.1 添加元素
public boolean add(E e) {
//先判断是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;//当前size位置添加元素,之后size后移一位
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//当前数组等于初始化时的数组的话---->返回默认容量10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//传入的最小容量大于当前数组长度的话,进行扩容grow
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容1.5倍
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);//数组复制
}
3.2 删除元素
public E remove(int index) {
//判断index是否合法
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
//后面元素前移一位
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//置为null,给gc回收
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
4. 总结
4.1 优缺点
-
底层是数组实现,随机访问模式,实现了
RandomAccess
接口查找比较快
-
添加元素也方便
-
删除和插入元素都有元素复制的操作,如果复制的元素多,就会耗费较多的性能
比较适合顺序添加、随机存储
4.2 ArrayList和Vector的区别
-
vector是线程安全的(不过基本淘汰了)
-
ArrayList线程不安全。重点是如何让它安全?
- 使用Collections的工具类:
Collections.synchronizedList(list);
4.3 为什么ArrayList的elementData用transient修饰
private transient Object[] elementData;
//1. 加快序列化速度
//2. 减小了序列化之后的文件大小
- 首先看ArrayList的定义
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
- ArrayList实现了序列化接口,用transient修饰是不想让ArrayList被序列化
ArrayList序列化的时候,可能elementData里面未必是慢满的(可能10个元素才填充了6个),那就没有必要序列化整个elementData了,因此ArrayList中重写了writeObject方法:每次序列化的时候调用该方法,只序列化有内容的元素
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out array length
s.writeInt(elementData.length);
// Write out all elements in the proper order.
for (int i=0; i<size; i++)
s.writeObject(elementData[i]);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}