ArrayList是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。继承于AbstractList,实现了List,RandomAccess,Cloneable,java.io.serializable这些接口。
和Vector不同,ArrayList中的操作不是线程安全的!!!所以建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。
继承关系如图
java.lang.Object ↳ java.util.AbstractCollection<E> ↳ java.util.AbstractList<E> ↳ java.util.ArrayList<E> public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}
ArrayList包含了两个重要的对象:elementData和size
(1)、elementData是Object类型的数组,它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数ArrayList(int initalCapacity)来执行它的初始容量为initalCapaccity;如果通过无参构造创建ArrayList 那么elementData默认容量为10。此数组的大小会根据ArrayList容量的增长而动态的增长,具体的增长方式,在ensureCapacity()方法中。
(2)、size就是动态数组的实际大小
构造函数
Arraylist 提供了三种方式的构造器,可以构造一个默认初始容量为10 的空列表,构造一个制定初始容量的空列表以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回的顺序排列的。
** * 构造一个指定初始容量的空列表 * @param initialCapacity ArrayList的初始容量 * @throws IllegalArgumentException 如果给定的初始容量为负值 */ 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的空列表 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * 构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回的顺序排列的 * @param c 包含用于去构造ArrayList的元素的collection * @throws NullPointerException 如果指定的collection为空 */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray()可能不会正确地返回一个 Object[]数组,那么使用Arrays.copyOf()方法 if (elementData.getClass() != Object[].class) //Arrays.copyOf()返回一个 Object[].class类型的,大小为size,元素为elementData[0,...,size-1] elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
此处说一下,ArrayList是如何创建一个默认初始容量为10的列表的。
在jdk1.6中 构造函数是这样的
public ArrayList() { this(10); //public ArrayList(int initialCapacity)中this.elementData = new Object[initialCapacity]; }
而之后的版本做了更改分为以下几步
1、初始情况:elementData=DEFAULTCAPACITY_EMPTY_EMEMENTDATA= {} ; // 此时size = 0
2、当我们向集合中新加一个元素的时候调用add方法会调用ensureCapacityInternal(size + 1) 方法,也就是ensureCapacityInternal(1)
3、在ensureCapacityInternal(int minCapacity) 方法中,当数组为空时,可得的minCapacity=DEFAULT_CAPACITY= 10,然后再调用ensureExplecitCapacity(minCapacity) 方法,即ensureExplicitCapacity(10);
4、在ensureExplicitCapacity(minCapacity)方法中调用grow(minCapacity)方法,也就是grow(10) ,这就是真正具体的数组扩容方法,在这里,通过elementData = Arrays.copyOf(elementData,10)实现了elementData数组初始容量为10的构造
/** * public方法,让用户能手动设置ArrayList的容量 * @param 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) { //当elementData为空时,ArrayList的初始容量最小为DEFAULT_CAPACITY(10) if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } //数组可被分配的最大容量;当需要的数组尺寸超过VM的限制时,可能导致OutOfMemoryError private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 增加数组的容量,确保它至少能容纳指定的最小容量的元素量 * @param minCapacity 期望的最小容量 */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //注意此处扩充capacity的方式是将其向右一位再加上原来的数,实际上是扩充了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); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
//将指定元素添加到集合中
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
//将指定元素添加到集合的指定位置
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; size++; }
//按照collection的迭代器返回的元素顺序,将所有元素添加到集合的尾部
public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount //将数组a[0,...,numNew-1]复制到数组elementData[size,...,size+numNew-1] System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; }
//从index开始将collection中所有元素添加到集合后面
public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); //判断参数index是否IndexOutOfBoundsException Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount int numMoved = size - index; if (numMoved > 0) //先将数组elementData[index,...,index+numMoved-1]复制到elementData[index+numMoved,...,index+2*numMoved-1] //即,将源数组中从index位置开始的后numMoved个元素统一后移numNew位 System.arraycopy(elementData, index, elementData, index + numNew, numMoved); //再将数组a[0,...,numNew-1]复制到数组elementData[index,...,index+numNew-1] System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; }
//删除指定索引的元素
public E remove(int index) {
//判断传入索引的合法性
rangeCheck(index);
modCount++; E oldValue = elementData(index);
//将数组中index之后的所有元素向前移动一位
int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved);
//将原数组最后一个元素滞空,方便gc清理 elementData[--size] = null; return oldValue; }
//删除集合中指定元素(第一个),Arraylist中允许存储重复元素
public boolean remove(Object o) { // 由于ArrayList中允许存放null,因此下面通过两种情况来分别处理。 if (o == null) { or (int index = 0; index < size; index++) if (elementData[index] == null) {
//集合内部私有的删除方法 不校验index 也没有返回值 fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }
//集合内部私有的删除方法 不校验index 也没有返回值
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 void clear() {
modCount++;
//将数组中所有元素制空 for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
}
//删除从fromIndex 到toIndex 之间的元素 包左不包右
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
//需要向前移动的元素的个数 共删除toIndex - fromIndex个元素
int numMoved = size - toIndex; System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); // clear to let GC do its work int newSize = size - (toIndex-fromIndex); for (int i = newSize; i < size; i++) { elementData[i] = null; } size = newSize; }
//删除集合中包含c中元素的元素
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c); //检查指定的对象c是否为空 return batchRemove(c, false); }
//删除集合中不包含在c中元素的所有元素 与removeAll()相反
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c); return batchRemove(c, true); }
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData; int r = 0, w = 0; //读写双指针 boolean modified = false; try { for (; r < size; r++)
//判断中 是否包含elementData[r]元素
if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } 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; }//将index索引的元素替换为element
public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }//判断集合中是否包含o元素
public boolean contains(Object o) {
//如果不存在返回-1 就返回false return indexOf(o) >= 0; }
//正向查找,返回o元素在集合中第一次出现的索引 如果不存在 返回-1
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; }
//逆向查找 ,返回o元素在集合中最后一次出现的索引 , 如果不存在返回-1
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; }
@SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; }
public E get(int index) {
//校验索引是否符合标准
rangeCheck(index);
return elementData(index); }//将elementData数组的容量调整为当前集合中元素的size
public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
//返回元素的个数
public int size() { return size; }//判断集合是否为空
public boolean isEmpty() { return size == 0; }
//因为ArrayList 实现了Cloneable,所以有拷贝功能
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); } }
//返回一个包含所有元素的数组
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
//如果a的长度足够,则将所有的集合中所有元素存放于a数组中,并返回
//如果a的长度不够,将新生成一个数组,长度等同于集合的长度,将所有元素存放于此数组中
@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; }