ArrayList介绍
List
接口的一个实现类,内部是用一个数组存储元素值,相当于一个可变大小的数组。
签名
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
可以看到ArrayList
继承了AbstractList
抽象类,它实现了List
接口的大多数方法。如果要实现一个不可变的List
,只要继承这个类并且实现get(int)
和size
方法。如果要实现可变的List
,需要覆盖set(int, E)
。另外,如果List
的大小是可变的,还要覆盖add(int, E)
和remove()
方法。
构造器
ArrayList
提供了三个构造器:
ArrayList()
ArrayList(Collection<? extends E> c)
ArrayList(int initialCapacity)
Collection
接口约定,每个集合类应该提供两个”标准”构造器,一个是无参数的构造器(上面第一个),另外一个是拥有单个参数(类型为Collettion
)的构造器(上面第二个)。ArrayList还提供了第三个构造器,其接受一个int值,用于设置ArrayLi的初始大小(默认大小为10)。
相关方法
trimToSize
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
用于把ArrayList
的容量缩减到当前实际大小,减少存储容量。其中的变量modCount
由AbstracList
继承而来,记录List发生结构化修改(structurally modified)的次数。elementData
中实际存储了ArrayList
的元素,在ArrayList
中声明为:private transient Object[] elementData;
变量size
是ArrayList
的元素数量,当size < oldCapacity
时,调用Arrays.copyOf
方法实现缩减。
indexOf
和 lasIndexOf
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;
}
这两个方法返回指定元素的下标,要区分参数是否为null
。lastIndexOf
和indexOf
类似,只不过是从后往前搜索。
ensureCapacity
public void ensureCapacity(int minCapacity) {
if (minCapacity > 0)
ensureCapacityInternal(minCapacity);
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(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);
}
这个方法可以确保ArrayList
的大小
add
和 addAll
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
add(int index, E element)
向指定位置添加元素,首先调用rangeCheckForAdd
检查index
是否有效,如果index > size || index < 0
将抛出异常。然后确保容量加1,调用System.arraycopy
把从index
开始的元素往后移动一个位置。最后把index
处的值设置为添加的元素。还有一个重载的add(E e)
方法是直接把元素添加到末尾。addAll(Collection<? extends E> c)
和addAll(int index, Collection<? extends E> c)
则分别是向末尾和指定位置添加Collection
中的所有元素。
remove
和 removeAll
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;
}
remove(Object o)
方法删除指定的元素。首先是查找元素位置,然后调用fastRemove(index)
删除,其代码如下:
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
//把index+1往后的元素都往前移动一个位置
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
重载的remove(int index)
方法用于删除指定位置的元素。removeRange(int fromIndex, int toIndex)
用于删除指定位置之间的所有元素。removeAll(Collection<?> c)
和retainAll(Collection<?> c)
代码如下:
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
它们都是通过调用batchRemove
方法实现的,其代码如下:
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++)
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;
}
这个方法有两个参数,第一个是操作的Collection
,第二个是一个布尔值,通过设置为true
或false
来选择是removeAll
还是retainAll
。try
里面的语句是把留下来的放在0到w之间,然后在finally
中第二个if
处理w之后的空间,第一个是在c.contains()
抛出异常时执行。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。