一. ArrayList简介
1)ArrayList是基于数组的动态扩容的一种数据结构,该类封装了一个动态再分配的Object[]数组,每一个类对象都有一个capacity属性,表示它们所封装Object[]数组的长度,当向ArrayList中添加元素时,该属性值会自动增加。如果ArrayList中添加大量元素,可使用ensureCapacity方法一次性增加capacity,可以减少增加重分配的次数提高性能。
2)ArrayList是线程不安全的Vector是线程安全的
二. 源码分析
1)
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
//默认初始容量
private static final int DEFAULT_CAPACITY = 10;
//空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认对象数组 其与EMPTY_ELEMENTDATA的区别是:当我们向数组中添加第一个元素时,知道数组该扩充多少。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//元素数据
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)我们可以看到ArrayList继承了AbstractList,这样会通用一些方法,并且实现了List,
RandomAccess(这个是一个标记性接口,通过查看api文档,它的作用就是用来快速随机存取,有关效率的问题,在实现了该接口的话,那么使用普通的for循环来遍历,性能更高,例如arrayList。而没有实现该接口的话,使用Iterator来迭代,这样性能更高,例如linkedList。所以这个标记性只是为了让我们知道我们用什么样的方式去获取数据性能更好)
Serializable实现序列化
3)构造函数
有初始容量的构造方法
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);
}
}
//无参构造方法
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
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)
//如果不是Object类型的,copy成object类型的
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array
this.elementData = EMPTY_ELEMENTDATA;
}
}
3)常用方法‘
- 添加方法
add()
//直接添加元素
public boolean add(E e) {
//先扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//下面看扩容代码
public void ensureCapacity(int minCapacity) {
//添加第一个元素时候,如果elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
//则分配默认大小
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
如果容量不够,下面方法是正真的扩容函数
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//扩容1.5倍后的大小
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);
}
//当newCapacity大于Integer.MAX_VALUE - 8则进行如下操作
//最大只能扩充到 Integer.MAX_VALUE :
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
add(int index, E element)
public void add(int index, E element) {
//检查扩容位置是否允许 > size && < 0 ?
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
//将index后的元素后移
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//插入元素
elementData[index] = element;
size++;
}
- 删除方法
public E remove(int index)
public E remove(int index) {
rangeCheck(index);
modCount++;
//先保留要删除的元素
E oldValue = elementData(index);
//要移动的元素个数
int numMoved = size - index - 1;
if (numMoved > 0)
把要移动的元素从index开始copy
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
把最后一个元素位置置空以便GC
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
public boolean remove(Object o)
public boolean remove(Object o) {
if (o == null) {
//该循环说明可以删除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;
}
//删除index位置的元素并且让最后位置元素置空以便gc
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; // clear to let GC do its work
}
public boolean removeAll(Collection<?> c)
public boolean removeAll(Collection<?> c) {
//确定c不为空
Objects.requireNonNull(c);
//正真的删除操作
return batchRemove(c, false);
}
//批量删除方法
private boolean batchRemove(Collection<?> c, boolean complement) {
// 在本地方法中拿到一个ArrayList中相同的数组
final Object[] elementData = this.elementData;
//r代表read, w代表write
int r = 0, w = 0;
boolean modified = false;
try {
//在try代码块中对删除的元素进行变化
for (; r < size; r++)
//这个if判断中的complement= false说明只有c中不包含elementData中的元素才进行
//elementData[w++] = elementData[r];操作,也就是操作不需要删除的元素
//那么elementData[w++] = elementData[r]到底做了啥呢? 它是把本方法中的
//elementData里面的元素不需要删除的元素从0开始复制到ArrayList的elementData中
//ArrayList指的是ArrayList<> list = new ArrayList<>(); list.removeAll(Collection c)中的list
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
//即使中间throw出错,也会执行下面代码, if (r != size)该if操作是将出错后剩下的元素copy进ArrayList的elementData中,
//就当出错的index后的元素也是不删除的元素
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
// if (w != size)判读是否有删除的元素,如果r==size , w== size说明把本方法中的elementData
//全部复制进入ArrayList的elementData中说明没有删除的元素
//如果w != size则0到w之间的元素为不删除的元素,也就是elementData与c没有交集的元素
//所有w后面的元素全部置空gc modified = true;完成删除
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
- clear()
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}