Java容器类的完整分类如图:
其中java.util.List属于Collection的子类,继承关系为:
List作为一个接口提供了基本的集合操作:
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List<E> subList(int fromIndex, int toIndex);
常用的ArrayList与LinkedList都是实现该接口,重写其中的方法
java.util.ArrayList的继承关系为:
ArrayList对象的本质为elementData数组,size记录数组元素数量
private transient Object[] elementData;
private int size;
注意这里elementData数组是transient的,但ArrayList对象仍然可以序列化和反序列化,是因为ArrayList重写了writeObject和readObject方法,在序列化与反序列化时会使用自己实现的方法来进行操作。
参数为泛型的构造方法
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
trimToSize方法
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = Arrays.copyOf(elementData, size);
}
}
该方法是将数组缩小为size大小,因为数组每次增长都会申请多一些空间,该方法就是将预留的元素空间去掉,最小化ArrayList对象的存储空间,注意该方法中有一个参数modCount,该参数来源于AbstracList,记录了list对象的修改次数,由于ArrayList不是进程安全的,每次add,remove等操作时都会修改modCount,在使用迭代器遍历ArrayList对象时,迭代器会将modCount与expectedModCount进行比较,如果两数不想等则抛出异常(迭代器在创建时将modCount赋给expectedModCount)。add方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
扩容后在数组中添加元素,其中扩容的实现如下:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == 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);
}
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
ArrayList在扩容前先判断原有空间是否为空,若原有空间为空(即ArrayList为空)则暂定扩容大小取DEFAULT_CAPACITY(10)与minCapacity的最大值
elementData数组现有大小不能满足扩容要求,则调用grow方法
在grow方法中,数组扩容机制为newCapacity = oldCapacity + (oldCapacity >> 1),oldCapacity >> 1为二进制移位,即除以2,默认扩容为原来的1.5倍
这样扩容后仍不能满足要求的情况下,指定扩容大小为minCapacity(即参数指定的大小),成功扩容后还要判断新容量大小是否大于MAX_ARRAY_SIZE (Integer.MAX_VALUE - 8),在大于的情况下调用hugeCapacity方法检查是否溢出,最大可运行的数组大小为Integer.MAX_VALUE,在Integer.MAX_VALUE 仍不满足要求的情况下应该使用其他存储方式。
to be continued...