Java ArrayList & LinkedList 解析

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/OOC_ZC/article/details/84174747

ArrayList 解析

ArrayList 类似于动态数组,与Vector的区别主要是Vector是线程安全的。

1. 类定义:

实现了 RandomAccess 接口,因此支持随机访问。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

数组默认大小为10:
private static final int DEFAULT_CAPACITY = 10;

2. 扩容:

添加元素时使用ensureCapacityInternal()方法来保证容量足够,如果不够时,需要使用 grow() 方法进行扩容,新容量的大小为 oldCapacity + (oldCapacity >> 1),也就是旧容量的 1.5 倍。

扩容操作需要调用 Arrays.copyOf() (Array类的静态方法)把原数组整个复制到新数组中,这个操作代价很高,因此最好在创建 ArrayList 对象时就指定大概的容量大小,减少扩容操作的次数。

3. 删除:

因为是数组,删除操作时间复杂度是O(N), 源码:

public E remove(int index) {
    rangeCheck(index);  // 如果index越界,拋越界异常

    modCount++;  // 记录ArrayList 结构发生变化的次数
    E oldValue = elementData(index); // 保留,结尾返回

    int numMoved = size - index - 1; // 需要ModCount移动的元素的数量
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
        // 调用 System.arraycopy() 将 index+1 后面的元素都复制到 index 位置上
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

4. modCount:

其中的modCount引人注意,modCount 用来记录 ArrayList 结构发生变化的次数。
在这里插入图片描述

  • modCount 定义在抽象类 AbstractList中,结构发生变化是指添加或者删除至少一个元素的所有操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化。

  • 在进行序列化或者迭代等操作时,需要比较操作前后 modCount 是否改变,如果改变了需要抛出 ConcurrentModificationException。

  • 如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。

  • fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。(这里就用modCount来实现fail-fast)

比如序列化前后会比较modCount,如modCount增长则抛出异常:

private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    s.defaultWriteObject();

    // Write out size as capacity for behavioural compatibility with clone()
    s.writeInt(size);

    // Write out all elements in the proper order.
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }

    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

LinkedList 解析:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

基于双向链表实现,使用 Node 存储链表节点信息。

private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

每个LinkedList实例存储了 first 和 last 指针:

transient Node<E> first;
transient Node<E> last;

LinkedList 结构图:
在这里插入图片描述

LinkedList 同样也维护 modCount 实例变量,改变结构时也会增加modCount。

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

猜你喜欢

转载自blog.csdn.net/OOC_ZC/article/details/84174747
今日推荐