ArrayList
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
ArrayList继承于AbstractList,实现了List, RandomAccess, Cloneable, Serializable接口。
RandomAccess 这个接口中并没有任何方法,这个接口仅做为可以快速访问的标志。
构造函数:
/**
* 使用指定的初始容量值构造一个空的list。
*
* @param initialCapacity list 的初始容量
* @throws IllegalArgumentException 如果指定的initialCapacity是负数就抛出该错误
*/
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);
}
}
/**
* 使用默认的初始值10来构造一个空的list
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/** 使用指定集合的元素按照其顺序构造一个list,
* @param c 元素被放入list 的集合集合
* @throws NullPointerException 如果指定的集合是null抛出该错误
*/
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)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
增
/**
* 在list 的尾部添加一个指定的元素
*
* @param e 在list中添加的元素
* @return true (as specified by {@link Collection#add}) 添加成功后返回true
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
在add方法中,首先调用了ensureCapacityInternal(size + 1);
方法。作用是确保list的空间足够。
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
transient Object[] elementData; // non-private to simplify nested class access
其中又调用了计算容量的方法calculateCapacity()
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
该方法是判断elementData
是否为空,如果为空,则将默认容量与传入的数值比较,返回一个较大的数值。如果elementData
不为空,则返回传入的数值。
ensureExplicitCapacity
方法如下:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
modCount用于记录对象的修改次数,比如增、删、改,也基本存在于非线程安全的集合类中
如果传入的数值比elementData
要大,那么就需要对数组进行扩容。
扩容机制:
grow方法
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
* 虚拟机分配数组的时候会保留一些关键字,因此尝试分配空间的时候会造成oom错误。
*/
private void grow(int minCapacity) {
// overflow-conscious code 溢出-感知代码
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 右移一位,相当于除以2,这里就是新的容量等于原来容量的3/2
if (newCapacity - minCapacity < 0) // 如果得到的新数值小于0,说明存在溢出
newCapacity = minCapacity; // 那么新容量就等于传入的数值
if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果新容量比MAX_ARRAY_SIZE要大
newCapacity = hugeCapacity(minCapacity); //
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);// 复制一个 newCapacity 大小的新数组。
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow // 如果产生溢出
throw new OutOfMemoryError(); // 抛出OutOfMemoryError
return (minCapacity > MAX_ARRAY_SIZE) ? // 没有溢出,如果minCapacity大于MAX_ARRAY_SIZE就返回Integer.MAX_VALUE
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
在指定位置插入元素
/**
* 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); //检查index 是否合法
ensureCapacityInternal(size + 1);
System.arraycopy(elementData, index, elementData, index + 1,size - index);
elementData[index] = element;
size++;
}
public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
src : 原数组
srcPos : 原数组指定位置(指定位置开始)
dest : 目标数组
destPos : 目标数组指定位置(指定位置开始)
length : 移动的元素数量
删
/**
* 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); // 检查index,如果大于list的长度则抛出IndexOutOfBoundsException异常
modCount++;
E oldValue = elementData(index); // 将该数据取出,存放于oldValue
int numMoved = size - index - 1; // 数组要移动元素的个数
if (numMoved > 0) // 如果要移动的元素个数大于0
System.arraycopy(elementData, index+1, elementData, index,
numMoved); // 调用System.arraycopy方法进行复制数组
elementData[--size] = null; // clear to let GC do its work 让GC去清理
return oldValue;
}
改
/**
* 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;
}
就是先检查index,然后直接对数组进行修改,赋值。
查
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
直接访问数组下标
主动扩容
/**
* Increases the capacity of this ArrayList instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)?0: DEFAULT_CAPACITY;
// 空表就给minExpand赋值为0,否则赋值为默认容量
if (minCapacity > minExpand) { // 判断是否大于minCapacity,是否继续扩容,与上面的扩容机制是一致的
ensureExplicitCapacity(minCapacity);
}
}
与linkedlist 的区别
linkedlist 是链表结构,链表就不存在扩容问题。链表的结构特点注定linkedlist是删除和插入操作快,而读速度慢。
而ArrayList 就很适合与读操作,但是进行插入删除就很慢。在不进行扩容的情况下,在list的尾部进行插入操作还是很快的。
线程是否安全
线程不安全。
可以使用Vector ,Vector很多方法都是经过synchronized
关键字进行修饰的,因此在效率上并不是那么理想。可以考虑使用Collections.synchronizedList(new ArrayList());
方法来对ArrayList进行包装。