转载请注明原文地址: http://zk-chs.iteye.com/blog/2250804
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
上面是是ArrayList类的定义,它继承了抽象类AbstractList,但是真正继承的方法只有equals和hashCode,
别的方法在ArrayList 中都有自己的重新实现;
List接口在AbstractList中已经实现,这里是为了表明一下,没有太大含义;
RandomAccess没有方法,表明ArrayList支持快速随机访问;
实 现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制,如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常;
类通过实现 java.io.Serializable 接口以启用其序列化功能,未实现此接口的类将无法使其任何状态序列化或反序列化
transient Object[] elementData; // 我们用于存储数据的数组
private static final int DEFAULT_CAPACITY = 10; // 默认大小为10
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private int size; // elementDate中对象数量,不是length
protected transient int modCount = 0; // 用于并发使用
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
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);
}
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
EMPTY_ELEMENTDATA在使用带参数构造函数时使用;
DEFAULTCAPACITY_EMPTY_ELEMENTDATA在使用默认构造函数时使用;
DEFAULT_CAPACITY会在默认构造函数实例的第一次调用add方法时使用;
modCount:当迭代时,如果modCount发生了变化,那么抛出并发修改异常(ConcurrentModificationException);
关于ArrayList的域就介绍这么多,下面看看方法:
public boolean add(E e):
// 在当前列表末尾添加一个对象,而不是数组
public boolean add(E e) {
// 确认数组大小,并让modCount + 1
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// if判断用于第一次调用add,如果是使用无参构造函数,那么进入此方法,设置minCapacity为10
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // first add
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
// modCount自增,并判断数组大小是否足够,不够的话将增大数组(下面介绍grow)
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 判断数组大小是否足够
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity):这是private方法,不能使用
private void grow(int minCapacity) { // 传入需要的数组大小
// oldCapacity为当前数组大小
int oldCapacity = elementData.length;
// 设置新数组大小的值,为当前的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 当addAll时可能新数组大小也不够
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// newCapacity可能会溢出,这里做判断
if (newCapacity - MAX_ARRAY_SIZE > 0) // MAX_ARRAY_SIZE = 2147483639
newCapacity = hugeCapacity(minCapacity);
// 使用Arrays扩展数组至newCapacity
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 : //2147483647
MAX_ARRAY_SIZE; // 2147483639
}
public boolean addAll(Collection<? extends E> c):
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray(); // 传入集合的数组显示
int numNew = a.length;
ensureCapacityInternal(size + numNew); // 同上
// 将a的numNew长度的元素添加到elementDate的末尾
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew; // 对象数量增长numNew
return numNew != 0; // 如果c刚刚创建没有调用add,那么numNew会为0
}
public void add(int index, E element) 和 public boolean addAll(int index, Collection<? extends E> c):
// 从指定索引位置插入元素
public void add(int index, E element) {
rangeCheckForAdd(index); // 判断插入位置是否越界
// 和add没什么不同
ensureCapacityInternal(size + 1); // Increments modCount!!
// 这就是我们常说的后移一位,其实是从指定位置开始复制
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
// 同上
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;
}
// 用于add和addAll 判断传入的索引值index是否越界
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
需要注意:不管addAll添加多少元素,modCount只会自增1!!!
public E get(int index):
public E get(int index) { // 获取指定位置元素
rangeCheck(index); // 注意 这里不是rangeCheckForAdd,下面介绍
return elementData(index);
}
public E set(int index, E element):
// 替换指定索引位置的元素,返回原位置元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
public E 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); // 相当于index+1后的元素前移一位
elementData[--size] = null; // clear to let GC do its work 通知jvm回收,防止内存泄漏
return oldValue; // 返回从list中移除的元素
}
// 这里仅与size比较,小于0数组本身会抛异常
private void rangeCheck(int index) {
if (index >= size) // 防止index在size与elementDate.length之间
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 返回索引位置元素
E elementData(int index) {
return (E) elementData[index];
}
public boolean 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?因为不需要再做检查,后面与remove相同
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 trimToSize():
// 将当前列表大小修改为当前元素size大小,释放被占用的空间
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size); // 复制size个元素,即数组大小变成size
}
}
public int size() 和 public boolean isEmpty():
public int size() {
return size; // 直接返回size
}
public boolean isEmpty() {
return size == 0;
}
public boolean contains(Object o):
// 是否包含指定元素,
public boolean contains(Object o) {
return indexOf(o) >= 0; // indexOf下面介绍
}
public int indexOf(Object o) 和 public int lastIndexOf(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;
}
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;
}
public Object clone():
// 为浅拷贝,不会拷贝数组内元素,两个列表引用相同的元素
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) { // 实现了Cloneable就不会出现
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
public Object[] toArray():
// 返回一个复制的数组,大小为size,而不是elementData.length,含有elementData中所有元素
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
public <T> T[] toArray(T[] a):
// 传入一个指定类型的数组
public <T> T[] toArray(T[] a) {
if (a.length < size) // 如果a长度小于size,那么直接复制elementData,大小为size
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
// 否则从a的0索引开始复制,而且a[size]会被设置为null !!!!!
// 如果你的数组很重要,那就小心点这个方法
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
public void clear():
// 清空当前列表,但是已经申请的空间大小(elementData.length)不会变
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
public void ensureCapacity(int minCapacity):
// 保证当前列表至少有minCapacity的大小
public void ensureCapacity(int minCapacity) {
// minExpand为0或为10
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 ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
protected void removeRange(int fromIndex, int toIndex):
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex; // 要移动的元素数量
// 将从toIndex开始,共numMoved个元素移动到fromIndex的位置
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
// 移除范围内元素后新的size大小
int newSize = size - (toIndex-fromIndex);
// 将复制的多余的数组空间设置为空,使gc可以回收,防止内存泄漏
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
public boolean removeAll(Collection<?> c) 和 public boolean retainAll(Collection<?> c):
// 删除所有与c中任一对象相同的对象,从下面到contains我们能知道是调用equals比较
public boolean removeAll(Collection<?> c) {
// 判断是否为空,为空抛出空指针
Objects.requireNonNull(c);
return batchRemove(c, false);
}
// 保留所有与c中任一对象相同的对象
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
// 批量删除,不建议使用,contains每次都要遍历,效率低下
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++)
// contains每次都要遍历
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
// finally语句块,即使contains抛出异常也会执行
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;
}
public List<E> subList(int fromIndex, int toIndex):
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size); // 常规的判断,见下
return new SubList(this, 0, fromIndex, toIndex); // 内部类SubList,后面介绍
}
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}
下面看看内部类SubList
private class SubList extends AbstractList<E> implements RandomAccess
除了是private没什么特别的
// 接着是域和构造函数,传入的list作为parent引用的对象
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex; // 截取的新列表的元素数量
this.modCount = ArrayList.this.modCount;
}
可以看到sublist的所有状态都是与传入的parent相关的;
如果你看了sublist的源码的话,你会发现它操作的就是parent的elementData数组;
只是每个方法添加了个offset而已,方法内容都是一样的,这里就不再重复了;
ArrayList的迭代器有2种;分别是Itr和ListItr;
private class Itr implements Iterator<E>
private class ListItr extends Itr implements ListIterator<E>
List比Itr多了操作对象的方法(例如add,set,previous等等);
下面是调用迭代器的方法:
// ListIterator支持从指定索引开始迭代
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
public ListIterator<E> listIterator() {
return new ListItr(0);
}
public Iterator<E> iterator() {
return new Itr();
}
多看集合容器源码对于我们理解和使用容器是很有好处的,而且可以更好的在编写并发代码
并发处理一定要良好的运用各个集合容器,以及扩展的concurrent下的线程安全容器(并非一定安全)
如果仅仅使用像vector一样的全部方法synchronized的集合的话,那么效率会非常低;
跑题了,希望能够一起进步吧...