手撕源码(四)LinkedList(JDK8)

1.使用示例

public static void main(String[] args) {
    List<String> list = new LinkedList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    System.out.println(list.get(0));
    System.out.println(list.remove(1));
    System.out.println(list.size());
}

执行结果:

在这里插入图片描述

2.new LinkedList<>() 解析

/**
 * Constructs an empty list.
 * ------------------------------
 * 构建一个空的列表
 */
public LinkedList() {
}

3.new LinkedList<>(Collection c) 解析

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 * ------------------------------
 * 按照指定集合的迭代器返回的顺序,构建一个包含指定元素的列表
 *
 * @param  c the collection whose elements are to be placed into this list
 * @throws NullPointerException if the specified collection is null
 * ------------------------------
 * @param  c 其元素将被放入此列表的集合
 * @throws NullPointerException 如果指定的集合为空
 */
public LinkedList(Collection<? extends E> c) {
    // 构建一个空的列表
    this();
    // 按照指定集合的迭代器返回的顺序,将指定集合中的所有元素追加到该列表的末尾。
    addAll(c);
}

3.1 链表长度

transient int size = 0;

3.2 addAll() 解析

/**
 * Appends all of the elements in the specified collection to the end of
 * this list, in the order that they are returned by the specified
 * collection's iterator.  The behavior of this operation is undefined if
 * the specified collection is modified while the operation is in
 * progress.  (Note that this will occur if the specified collection is
 * this list, and it's nonempty.)
 * ------------------------------
 * 按照指定集合的迭代器返回的顺序,将指定集合中的所有元素追加到该列表的末尾。如果
 * 在操作进行期间修改了指定集合,则此操作的行为是未被定义的。(注意,如果指定的集
 * 合是一个非空的列表,就会发生这种情况。)
 *
 * @param c collection containing elements to be added to this list
 * @return {@code true} if this list changed as a result of the call
 * @throws NullPointerException if the specified collection is null
 * ------------------------------
 * @param c 要添加到此列表的元素集合
 * @return 如果此列表因调用而更改,则为true
 * @throws NullPointerException 如果指定的集合为空
 */
public boolean addAll(Collection<? extends E> c) {
    // 从指定位置开始,将指定集合中的所有元素插入此列表。
    return addAll(size, c);
}
3.2.1 第1个节点
/**
 * Pointer to first node.
 * Invariant: (first == null && last == null) ||
 *            (first.prev == null && first.item != null)
 * ------------------------------
 * 指向第一个节点的指针。
 * 不变式:(第一个节点的指针为null 并且 最后一个节点的指针为null) 或者
 *        (第一个节点的指针的上一个指针为null 并且 第一个节点不为null)
 */
transient Node<E> first;

注意:这个不变式不是说任何情况下都是绝对成立的,目前还不清楚具体含义,了解的大佬欢迎评论补充。

不变式不成立场景:

List<Object> list = new ArrayList();
list.add(null);

添加一个null之后,firstlast 都变成 new Node(null, null, null),导致 first != null && first.item == null,使得不变式不成立。

3.2.2 最后1个节点
/**
 * Pointer to last node.
 * Invariant: (first == null && last == null) ||
 *            (last.next == null && last.item != null)
 * ------------------------------
 * 指向最后一个节点的指针。
 * 不变式:(第一个节点的指针为null 并且 最后一个节点的指针为null) 或者
 *        (最后一个节点的指针的下一个指针为null 并且 最后一个节点不为null)
 */
transient Node<E> last;

注意:这个不变式不是说任何情况下都是绝对成立的,目前还不清楚具体含义,了解的大佬欢迎评论补充。

不变式不成立场景:

List<Object> list = new ArrayList();
list.add(null);

添加一个null之后,firstlast 都变成 new Node(null, null, null),导致 last != null && last.item == null,使得不变式不成立。

3.2.3 结构修改次数
/**
 * The number of times this list has been <i>structurally modified</i>.
 * Structural modifications are those that change the size of the
 * list, or otherwise perturb it in such a fashion that iterations in
 * progress may yield incorrect results.
 * ---------------------------
 * 这个列表在结构上被修改的次数。结构修改是指改变列表的大小,或者以某种方式扰乱
 * 列表,从而使进行中的迭代可能产生不正确的结果。
 *
 * <p>This field is used by the iterator and list iterator implementation
 * returned by the {@code iterator} and {@code listIterator} methods.
 * If the value of this field changes unexpectedly, the iterator (or list
 * iterator) will throw a {@code ConcurrentModificationException} in
 * response to the {@code next}, {@code remove}, {@code previous},
 * {@code set} or {@code add} operations.  This provides
 * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
 * the face of concurrent modification during iteration.
 * ---------------------------
 * 该字段由iterator和listtiterator方法返回的迭代器和列表迭代器实现使用。如果该
 * 字段的值发生意外变化,迭代器(或列表迭代器)将抛出ConcurrentModificationException,
 * 以响应next、remove、previous、set或add操作。这提供了快速故障行为,而不是在
 * 迭代期间面对并发修改时的不确定性行为。
 *
 * <p><b>Use of this field by subclasses is optional.</b> If a subclass
 * wishes to provide fail-fast iterators (and list iterators), then it
 * merely has to increment this field in its {@code add(int, E)} and
 * {@code remove(int)} methods (and any other methods that it overrides
 * that result in structural modifications to the list).  A single call to
 * {@code add(int, E)} or {@code remove(int)} must add no more than
 * one to this field, or the iterators (and list iterators) will throw
 * bogus {@code ConcurrentModificationExceptions}.  If an implementation
 * does not wish to provide fail-fast iterators, this field may be
 * ignored.
 * ---------------------------
 * 子类使用此字段是可选的。如果子类希望提供快速失败迭代器(和列表迭代器),那么它只
 * 需要在其add(int, E)和remove(int)方法(以及它覆盖的导致列表结构修改的任何其他
 * 方法)中增加该字段。单个调用add(int, E)或remove(int)必须向该字段添加不超过一
 * 个,否则迭代器(和列表迭代器)将抛出虚假的concurrentmodificationexception。如
 * 果实现不希望提供快速失败迭代器,则可以忽略此字段
 */
protected transient int modCount = 0;
3.2.4 addAll() 解析
/**
 * Inserts all of the elements in the specified collection into this
 * list, starting at the specified position.  Shifts the element
 * currently at that position (if any) and any subsequent elements to
 * the right (increases their indices).  The new elements will appear
 * in the list in the order that they are returned by the
 * specified collection's iterator.
 * ------------------------------
 * 从指定位置开始,将指定集合中的所有元素插入此列表。将当前在该位置的元素(如果
 * 有的话)和任何后续元素向右移动(增加它们的索引)。新元素将按照指定集合的迭代
 * 器返回的顺序出现在列表中。
 *
 * @param index index at which to insert the first element
 *              from the specified collection
 * @param c collection containing elements to be added to this list
 * @return {@code true} if this list changed as a result of the call
 * @throws IndexOutOfBoundsException {@inheritDoc}
 * @throws NullPointerException if the specified collection is null
 * ------------------------------
 * @param index 从指定集合中插入第一个元素的索引。
 * @param c 包含要添加到此列表的元素的集合。
 * @return 如果此列表因调用而更改,则为true。
 * @throws IndexOutOfBoundsException 如果索引超出范围(index < 0 || 
 * index > size())。
 * @throws NullPointerException 如果指定的集合为空。
 */
public boolean addAll(int index, Collection<? extends E> c) {
    // 判断参数是否是迭代器或加法操作的有效位置的索引。
    checkPositionIndex(index);

    // 集合转数组
    Object[] a = c.toArray();
    int numNew = a.length;
    // 空集合则不做任何操作
    if (numNew == 0)
        return false;

    // pred-前节点,succ-后节点,用于后续在前节点和后节点之间插入数据
    Node<E> pred, succ;
    // 判断如果索引在末尾,直接取值
    if (index == size) {
        // 后节点 -> null
        succ = null;
        // 前节点 -> 最后一个节点
        pred = last;
    } else {
        // 如果索引不在末尾,遍历取值
        // 后节点 -> 索引处的节点
        succ = node(index);
        // 前节点 -> 索引处节点的前节点
        pred = succ.prev;
    }

    // 遍历待新增的元素数组,添加到当前链表中
    for (Object o : a) {
        // 强制类型转换
        @SuppressWarnings("unchecked") E e = (E) o;
        // 封装新节点
        Node<E> newNode = new Node<>(pred, e, null);
        // 如果没有前节点
        if (pred == null)
            // 新节点为第一个节点
            first = newNode;
        else
            // 将前节点的下一个指针指向新节点
            pred.next = newNode;
        // 将新节点作为前节点
        pred = newNode;
    }

    // 如果插入位置后面没有节点
    if (succ == null) {
        // 将当前节点作为最后节点
        last = pred;
    } else {
        // 如果插入位置后面有节点,则进行连接
        // 当前节点的下一个节点为后节点
        pred.next = succ;
        // 后节点的上一个节点为当前节点
        succ.prev = pred;
    }

    // 增加链表长度
    size += numNew;
    // 结构修改次数+1
    modCount++;
    // 列表有更改,返回true
    return true;
}
3.2.5 checkPositionIndex() 解析
private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
3.2.5.1 isPositionIndex() 解析
/**
 * Tells if the argument is the index of a valid position for an
 * iterator or an add operation.
 * ------------------------------
 * 判断参数是否是迭代器或加法操作的有效位置的索引。
 */
private boolean isPositionIndex(int index) {
    return index >= 0 && index <= size;
}
3.2.6 node() 解析
/**
 * Returns the (non-null) Node at the specified element index.
 * ------------------------------
 * 返回指定元素索引处的(非空)节点
 */
Node<E> node(int index) {
    // assert isElementIndex(index);

    // 判断如果索引处于列表位置的上半段
    if (index < (size >> 1)) {
        // 从前往后遍历,index < 0则取第一个节点
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        // 如果索引处于列表位置的下半段
        // 从后往前遍历,index > size则取最后一个节点
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}
3.2.7 new Node<>() 解析
/**
 * Node构造方法
 */
Node(Node<E> prev, E element, Node<E> next) {
    this.item = element;
    this.next = next;
    this.prev = prev;
}

4.add() 解析

/**
 * Appends the specified element to the end of this list.
 * ------------------------------
 * 将指定的元素追加到此列表的末尾。
 *
 * <p>This method is equivalent to {@link #addLast}.
 * ------------------------------
 * 这个方法等价于addList。。
 *
 * @param e element to be appended to this list
 * @return {@code true} (as specified by {@link Collection#add})
 * ------------------------------
 * @param e 要添加到列表中的元素
 * @return true(由Collection.add指定)
 */
public boolean add(E e) {
    // 将e链接为最后一个元素
    linkLast(e);
    return true;
}

4.1 linkLast() 解析

/**
 * Links e as last element.
 * ------------------------------
 * 将e链接为最后一个元素
 */
void linkLast(E e) {
    // 获取末尾元素
    final Node<E> l = last;
    // 将e封装为一个新节点,参考 3.2.7
    final Node<E> newNode = new Node<>(l, e, null);
    // 将指向最后一个节点的指针指向新元素
    last = newNode;
    // 判断原有末尾节点是否指向空
    if (l == null)
        // 说明当前链表为空,将指向第一个节点的指针指向新元素 
        first = newNode;
    else
        // 说明当前链表不为空,将原有末尾元素下一个节点的指针指向新元素
        l.next = newNode;
    // 链表长度+1
    size++;
    // 结构修改次数+1
    modCount++;
}

5.get() 解析

/**
 * Returns the element at the specified position in this list.
 * ------------------------------
 * 返回列表中指定位置的元素。
 *
 * @param index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 * ------------------------------
 * @param index 要返回元素的索引
 * @return 在此列表中指定位置的元素
 * @throws IndexOutOfBoundsException 如果索引超出范围(index < 0 ||
 * index >= size())
 */
public E get(int index) {
    // 判断参数是否是现有元素的索引。
    checkElementIndex(index);
    // 返回指定元素索引处的(非空)节点,参考 3.2.6
    return node(index).item;
}

5.1 checkElementIndex() 解析

private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
5.1.1 isElementIndex() 解析
/**
 * Tells if the argument is the index of an existing element.
 * ------------------------------
 * 判断参数是否是现有元素的索引。
 */
private boolean isElementIndex(int index) {
    return index >= 0 && index < size;
}

6.remove() 解析

/**
 * Removes the element at the specified position in this list.  Shifts any
 * subsequent elements to the left (subtracts one from their indices).
 * Returns the element that was removed from the list.
 * ------------------------------
 * 移除此列表中指定位置的元素。将所有后续元素向左移动(从它们的索引中减去1).
 * 返回从列表中删除的元素。
 *
 * @param index the index of the element to be removed
 * @return the element previously at the specified position
 * @throws IndexOutOfBoundsException {@inheritDoc}
 * ------------------------------
 * @param index 要删除元素的索引
 * @return 之前在指定位置的元素
 * @throws IndexOutOfBoundsException 如果索引超出范围(index < 0 ||
 * index >= size())
 */
public E remove(int index) {
    // 判断参数是否是现有元素的索引,参考 5.1
    checkElementIndex(index);
    // 解除非空节点x的链接。
    return unlink(node(index));
}

6.1 unlink() 解析

/**
 * Unlinks non-null node x.
 * ------------------------------
 * 解除非空节点x的链接。
 */
E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;
    // next 用于记录待解除链接节点x的下一个节点
    final Node<E> next = x.next;
    // prev 用于记录待解除链接节点x的上一个节点
    final Node<E> prev = x.prev;

    // 判断节点x是否为第一个节点
    if (prev == null) {
        // 将指向第一个节点的指针指向next节点
        first = next;
    } else {
        // 将prev节点的下一个节点的指针指向next
        prev.next = next;
        // 将x节点的上一个节点的指针指向null
        x.prev = null;
    }

    // 判断节点x是否为最后一个节点
    if (next == null) {
        // 将指向最后一个节点的指针指向prev节点
        last = prev;
    } else {
        // 将next节点的上一个节点的指针指向prev
        next.prev = prev;
        // 将x的下一个节点的指针指向null(最后一个节点没有后节点)
        x.next = null;
    }

    // 将x节点的指针指向null,方便JVM回收内存
    x.item = null;
    // 链表长度-1
    size--;
    // 结构修改次数+1
    modCount++;
    // 返回删除节点指向的元素
    return element;
}

7.size() 解析

/**
 * Returns the number of elements in this list.
 * ------------------------------
 * 返回此列表中元素的个数。
 *
 * @return the number of elements in this list
 * ------------------------------
 * @return 列表中元素的个数
 */
public int size() {
    return size;
}

整理完毕,完结撒花~ 🌻

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不愿放下技术的小赵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值