ArrayList 源码解析
概述
ArrayList 是一个动态数组,容量可以动态增长。他是线程不安全的,允许元素为null。它的底层数据结构是数组,所以会占用一块连续的内存空间。它实现了
List<E>, RandomAccess, Cloneable, java.io.Serializable
接口。RandomAccess
代表List获取了随机访问功能,也就是通过下标获取元素对象的功能。
构造函数分析
定义
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
构造函数
执行完构造函数之后会构建出elementData数组和数量Size
/**
* Default initial capacity. 初始化容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 默认构造函数中的空数组
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储集合元素的底层实现:真正存放元素的数组
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
* transient 修饰表示elementData 不会被序列化, 因为elementData不是每次都是满的,每次都序列化会比较浪费时间
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
* 当前元素的数量
* @serial
*/
private int size;
/**
* Constructs an empty list with the specified initial capacity.
* 带初始化容量的构造函数
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
// 如果初始化容量大于 0 ,就新建一个长度为 initialCapacity 的Object 数组 这里没有修改Size(对比第三个构造)
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) { //如果初始化容量为 0 ,直接将空的对象数组赋值给 elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {// 容量小于 0 直接抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 默认构造方法,默认容量为10 ,
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
//将空数组赋值给 elementData
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
* 传入一个集合类作为参数的构造函数
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
// 使用Collection.toArray()方法获取到一个对象数组,并复制给elementData
elementData = c.toArray();
// size 是集合当前的容量,所以通过别的集合来构造的时候要给size复制
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)//当c.toArray出错的时候没有返回对象数组,
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 根据Class的类型去判断是去new一个对象数组还是去通过反射构造一个泛型数组,同时利用native函数,批量赋值元素至新数组中。
*/
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);
//利用native函数,批量赋值元素至新数组中
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
常用API分析
增加
add(E e)
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e; //在数组末尾增加一个元素,并且修改size
return true;
}
/**
* Default initial capacity. 默认初始化容量
*/
private static final int DEFAULT_CAPACITY = 10;
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//通过这个判断是否是使用默认构造函数初始化
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
//这个方法是用来进行扩容检查的
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//如果确定要扩容,需要修改modCount 记录修改的次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)// 如果传过来的容量大小比初始长度,执行扩容方法
grow(minCapacity);
}
/**
* 真正的扩容方法,默认扩容一半
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//新的容量 = 老容量 + 老容量的一半, 右移一位表示除以 2分之1
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);
}
/**
* Copies the specified array, truncating or padding with nulls (if necessary)
* so the copy has the specified length. For all indices that are
* valid in both the original array and the copy, the two arrays will
* contain identical values. For any indices that are valid in the
* copy but not the original, the copy will contain <tt>null</tt>.
* Such indices will exist if and only if the specified length
* is greater than that of the original array.
* The resulting array is of the class <tt>newType</tt>.
*
*
*/
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;
}
add(int index, E element)
添加元素 element 到 index 位置
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
* 添加元素到指定位置
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
rangeCheckForAdd(index);//判断索引是否越界,若越界就会抛异常
//扩容检查
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将指定下标空出,具体就是将index及其后的元素都往后挪动一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 赋值
elementData[index] = element;
// 长度加1
size++;
}
addAll(Collection<? extends E> c)
直接添加一个集合
/**
* Appends all of the elements in the specified collection to the end of
* this list, in the order that they are returned by the
* specified collection's Iterator. The behavior of this operation is
* undefined if the specified collection is modified while the operation
* is in progress. (This implies that the behavior of this call is
* undefined if the specified collection is this list, and this
* list is nonempty.)
*
* @param c collection containing elements to be added to this list
* @return <tt>true</tt> if this list changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
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;
}
addAll(int index, Collection<? extends E> c)
添加集合到指定位置
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index); //判断索引是否越界,若越界就会抛异常
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount 扩容检查
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved); // 移动复制数组
System.arraycopy(a, 0, elementData, index, numNew);// 复制数组完成批量复制
size += numNew;
return numNew != 0;
}
小结:先判断是否越界,是否需要扩容,如果扩容就需要复制数组,然后设置对应下标元素值。如果需要扩容,默认扩容一半,如果一半还不够,那么就用目标的size作为扩容后的容量。扩容成功后,会修改
modCount
删除
E remove(int index)
按照下标删除
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
* 移除数组中指定位置的元素,后续元素都要左移,并且下标减一
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index);//下标越界检查
modCount++;//记录修改次数
//获取要移除的元素
E oldValue = elementData(index);
//计算出需要左移的元素个数
int numMoved = size - index - 1;
//如果大于0说明有元素需要左移,如果等于0,说明移除的是最后一位
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);// index右侧的元素都左移一位,覆盖原来的元素
//最后一个元素赋值为null,会被GC
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
boolean remove(Object o)
移除指定元素
public boolean remove(Object o) {
if (o == null) { //如果元素为 null 遍历数组移除第一个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;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
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
}
修改
不会修改modCount,相对增删是高效的操作
/**
* Replaces the element at the specified position in this list with
* the specified element.
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
rangeCheck(index); //下标越界检查
// 取出元素
E oldValue = elementData(index);
// 覆盖元素
elementData[index] = element;
//返回老元素
return oldValue;
}
查询
不会修改modCount,相对增删是高效的操作
E elementData(int index) {
return (E) elementData[index];
}
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
清空
modCount 会修改
/**
* Removes all of the elements from this list. The list will
* be empty after this call returns.
*/
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
总结
- 在增删改查中,增会导致扩容,会修改modCount,删也会修改,改和查一定不会修改
- 扩容数组会导致复制数组,批量删除需要找到两个集合的交集然后复制数组操作,所以增和删比较低效,改和查比较高效。
补充
ArrayList 与 Vector 的区别
- ArrayList是线程不安全的,Vector里面的方法都有synchronized修饰,所以是线程安全的
- ArrayList扩容是扩充百分之五十,Vector扩容是翻倍的size。
网友评论