Java源码阅读-List

来源:互联网 发布:软件测试高级工程师 编辑:程序博客网 时间:2024/06/17 01:09

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...

0 0
原创粉丝点击