ArrayList的继承结构
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList的属性
// 底层数组默认的初始大小
private static final int DEFAULT_CAPACITY = 10;
// 调用有参构造器且传参为0时,分配此空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 调用无参构造器时,分配此空数组,需要区别于上面的空数组,在第一次添加元素对底层数据扩容时,实现不同
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 存储数据的底层数据
transient Object[] elementData;
// 底层数据中元素的个数
private int size;
// 要分配数组的最大大小,这是JVM的限制,尝试分配更大的空间可能导致OutOfMemoryError错误
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 这个属性在ArrayList的直接父类AbstractList中定义,记录添加、删除操作的次数,用于在FailFast机制中保护并发环境下集合数据的安全
protected transient int modCount = 0;
ArrayList的构造器
无参构造器
分配一个空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造器 ArrayList(int initialCapacity)
- 当自定义容量大于0时,分配指定大小的数组空间;
- 当自定义容量为0时,分配一个空数组 EMPTY_ELEMENTDATA;
- 当自定义容量小于0时,抛出IllegalArgumentException异常
- 需要注意的是,当试图分配超出MAX_ARRAY_SIZE的数组空间时,因为会被转化为int类型而导致溢出,成为一个负数,不会成功分配空间,而会抛出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);
}
}
有参构造器 ArrayList(Collection<? extends E> c)
- 如果集合c是空的,则返回名为EMPTY_ELEMENTDATA的数组
- 如果集合c非空,则elementData指向c转化后的Object数组
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
方法
add(E e, Object[] elementData, int s)
- private的用于add(E object)
- 在s位置添加元素e,如果在尾部添加则对原数组进行扩容,再添加
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
add(E object)
- 修改次数midCount+1
- 使用add(E e, Object[] elementData, int s)在尾部添加e
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
add(int index, E element)
- 指在 index的位置 ,插入一个新元素。
- 从要插入的位置开始的所有数据,都要往先后挪一位;然后再把要插入的数据放进去。
rangeCheckForAdd(int index):如果添加位置大于原数组长度或小于0,则抛出IndexOutOfBoundsException(outOfBoundsMsg(index))异常。
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
创建一个新数组elementData等于原数组,若elementData数组长度==s==size,则扩容。
之后进行数组copy在index左右两边复制后,最后在index添加element
public void add(int index, E element) {
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
private Object[] grow()
扩容方法
private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity)
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);
}
默认情况下,扩容后新数组的大小为旧数组大小的1.5倍,把旧数组的内容拷贝到新数组中。
特殊情况下,如果扩容后的1.5倍容量newCapacity仍然小于所需的最小容量,则扩容后的新数组大小为所需的最小容量;如果扩容后的大小大于ArrayList的最大限定大小,则调用hugeCapacity函数处理。
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
该函数会尝试分配更大的空间,如果所需的最小容量minCapacity未超过ArrayList设定的最大容量,则扩容后新数组的大小就为ArrayList设定的最大容量,否则也会分配长度为Integer.MAX_VALUE的新数组。在判断minCapacity与MAX_ARRAY_SIZE的大小之前,需要判断calculateCapacity函数计算得到的最小容量是否小于0,minCapacity是int类型,小于0表明已经溢出,即也超出了后面所要分配的最大空间大小Integer.MAX_VALUE,故而抛出OutOfMemoryError错误。
remove (int index)
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;
}
rangeCheck方法
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
remove (int index)方法,首先判断待删除的索引下标是否越界,如果越界则抛出IndexOutOfBoundsException异常,否则调用System.arrayCopy方法把待删除元素后面的元素依次向前移动1个索引距离,然后把数组的最后一个元素置为null,由GC机制回收内存空间,该方法返回被删除元素的值。
remove (Object o)
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函数,调用fastRemove方法进行删除,并返回true,反则,返回false。
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
}
fastRemove方法是基于下标删除,和remove (int index)方法逻辑相同,只不过这里的下标一定是正常的,不需要调用rangeCheck方法校验。
size()
public int size() {
return size;
}
isEmpty
public boolean isEmpty() {
return size == 0;
}
list.isEmpty和list == null的区别,list == null 表示没有指向具体的内存空间,而list.isEmpty表示指向了一块连续的存储空间,但这块存储空间还没有存储任何元素。
contains (Object o)
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
indexOf(Object o)
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;
}
从前往后找,找到符合条件的对象则返回索引,找不到返回-1。
lastIndexOf ()
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。
get(int index)
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
检查下标,如果合法则根据下标返回指定元素,否则,在rangeCheck方法中抛出IndexOutOfBoundsException异常。
set(int index, E element)
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
检查下标,如果合法则根据下标更新元素,并返回旧值,否则,在rangeCheck方法中抛出IndexOutOfBoundsException异常。
clear()
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
iterator ()
public Iterator<E> iterator() {
return new Itr();
}
返回一个Itr对象,Itr是ArrayList的内部类,实现了Iterator接口。
private class Itr implements Iterator<E>
Iterator提供了遍历的方法,Itr则对这些方法提供了具体实现,因此,iterator方法返回的是ArrayList的迭代器。