ArrayList 源码分析
ArrayList 是平时常用的数据存储结构,它基于动态数组,支持随机访问,值得一提的是:它是不安全的。造成这种不安全的原因主要是:在在多线程环境下,向 ArrayList 添加或移除时,会产生数组越界等问题。推荐使用 Vector、CopyOnWriteArrayList 代替。
ArrayList 与 Array 区别:
- Array 包含的是基本类型和对象类型,而ArrayList 只能包含对象类型
- Array 的大小的是固定的,所以在定义数组的时候尽量确定需要的数组大小,而ArrayList 的大小是动态变化的,当容量不足时能自动扩容
- ArrayList 可以看作Array的增强版,提供了更多的方法和特性,在查找等操作上更方便
定义
1 | public class ArrayList<E> extends AbstractList<E> |
ArrayList 支持泛型,继承了 AbstractList,在实现了List接口的同时,实现了一下三个接口:
- RandomAccess — 随机访问,即通过元素的序号快速获取对象
- Cloneable — 覆盖了 clone(),能被克隆
- Serializable — 支持序列化
属性
1 | private static final long serialVersionUID = 8683452581122892189L; |
其中,size 指 ArrayList 的大小,DEFAULT_CAPACITY 指在未定义 ArrayList大小的情况下,初始化 elementData 的长度为10
elementData 是 ArrayList 在存储数据时的 buffer,通过数组存储数据。同时,elementData 被 transient 修饰,所以在 ArrayList 序列化的时候,elementData 并不参与,而序列化的过程主要通过 writeObject(),readObject()实现。
构造方法
1 | /** |
具体方法
查找1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33/**
* 正序查找
* 判断查询对象是否为null, 若是则正序查找第一个值为 null 的对象,返回索引号
*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
/**
* 逆序查找
* 判断查询对象是否为null, 若是则逆序查找第一个值为 null 的对象,返回索引号
*/
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
拷贝1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* 通过super.clone(), 获取 ArrayList 的一个副本,
* 再设置 ArrayList 的 elementData 和 modCount 属性。因为拷贝的是新的副本,将新副本的 modCount 设为0。
*/
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
在拷贝的过程中,发现它调用了Arrays.copoOf(original, lenght),而Arrays.copy()又调用了System.arraycopy()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@SuppressWarnings("unchecked")
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
/**
* 这里的又调用了System.arraycopy()
*/
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
System.arraycopy()是个 本地方法,底层调用了 c++ 方法实现,使其的效率更高1
2
3public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
转化为数组1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/**
* 返回 elementData 的副本
*/
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
获取,修改元素1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33/**
* 通过索引,返回查询elementData 中的值,便于其他方法的操作
*/
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
// 数组越界检查
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* 先进行越界异常检查,判断 index < size 时,返回查询结果
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
/**
* 一样,先进行越界检查,将新值替代为旧值,返回旧值
*/
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
移除1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51/**
* 通过索引值删除
* System.arraycopy()将 elementData 的索引值后的元素向前移动,最后删除最后重复的元素值,size -1
*/
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;
}
/**
* 通过对象值删除
* 正序删除,当查找到要删除的值时,调用 fastRemove() 实现删除的具体操作
*/
public boolean remove(Object o) {
if (o == 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;
}
/**
* fastRemove() 相比于 remove(): 跳过 rangeCheck() 越界检查 和 不返回删除值,这样可以更快得删除元素
*/
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
}
清除
1 | /** |
添加
1 | /** |
扩容机制 (扩容机制在jdk 1.7开始做出了改动,主要改动:采用 位运算 替代之前的操作符, 加入 最大数组容量 的判断)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64/**
* 当需要的 容量空间 大于 默认容量,执行ensureExplicitCapacity(minCapacity)
*/
public void ensureCapacity(int minCapacity) {
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 ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
/**
* modcount+1
* 需求容量 大于 数组的大小时,执行grow()
*/
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 扩容的具体方法
* oldCapacity + ( oldCapacity >> 1) 位运算向右移一位,使得oldCapacity 为原来的1.5倍
* 当 newCapacity 大于数组的最大长度时,调用hugeCapacity()调整
* 拷贝新的 elementData 副本
*/
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);
}
/**
* 调整容量
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
序列化(序列化的过程是将size, elementData中的所有对象写入或者读取),不采用将整个elementData写入是因为节省空间
1 | /** |
排序 (ArrayList的排序采用的是Array的并归排序)
1 | /** |