LinKedList源码分析

LinKedList源码分析

属性分析

// 集合大小
transient int size = 0;

/**
 * Pointer to first node.
 * Invariant: (first == null && last == null) ||
 *            (first.prev == null && first.item != null)
   指向第一个节点的指针。 
   *不变式:(第一个== null &&最后一个== null)||(first.prev == null && first.item!= null)
 */
transient Node<E> first;

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

protected transient int modCount = 0; // 响应快速失败,状态记录参数

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;
        }
    }

方法分析

add
/**
 * Appends the specified element to the end of this list.
 *
 * <p>This method is equivalent to {@link #addLast}.
 *
 * @param e element to be appended to this list
 * @return {@code true} (as specified by {@link Collection#add})
   将指定的元素追加到此列表的末尾。 * * <p>此方法等效于{@link #addLast}。 * * @要附加到此列表的参数元    素* @返回{@code true}(由{@link Collection#add}指定
 */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    /**
     * Links e as last element.
       将e链接为最后一个元素。
     */
    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;
        // 集合大小加1
        size++;
        // 状态记录参数
        modCount++;
    }
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 要返回的元素的索引索引
   * @返回 此列表中指定位置的元素* 
   @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    // 检查下标
    checkElementIndex(index);
    // 拿取元素
    return node(index).item;
}
/**
 * 返回指定元素索引处的(非空)节点
*/		
Node<E> node(int index) {
    // 调用前先验证下标是否越界
    // assert isElementIndex(index);
    // (index < size/2的一次方 位移符号优先级低于运算符?(括起来):
    if (index < (size >> 1)) {
        // 一刀切成两份,索引小于中间值,则从首节点开始遍历
        Node<E> x = first;
        // 拿到当前节点,因为调用next 循环比下标数减1,正好使用下标作为判断的闭区间。
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else { // 索引大于等于中间值,则从尾节点开始遍历, 奇数尾节点多一个
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}
// 检查元素索引是否越界
private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
    /**
     * 判断参数是否为现有元素的索引。
     */
private boolean isElementIndex(int index) {
    // index 0 size 1
    return index >= 0 && index < size;
}
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.
 *
 * @param index the index of the element to be removed
 * @return the element previously at the specified position
 * @throws IndexOutOfBoundsException {@inheritDoc}
   删除此列表中指定位置的元素。将任何后续元素向左移动(从其索引中减去一个)。 
   返回从列表中删除的元素。
   @param index要删除的元素的索引
   @返回 先前在指定位置的元素* @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E remove(int index) {
    // 检查下标是否越界
    checkElementIndex(index);
    // 先调用node方法找到指定的节点,
    return unlink(node(index));
}

   /**
     * 取消链接非空节点x。
     */
E unlink(Node<E> x) {
    // assert x != null;
    // 先保存被删除节点的值,提供返回
    final E element = x.item;
    // 拿到被删除节点的后一个节点
    final Node<E> next = x.next;
    // 拿到被删除节点的前一个节点
    final Node<E> prev = x.prev;
    // 判断被删除的节点,是否为首节点
    if (prev == null) {
        // 是首节点,指向改为被删除节点的下一个节点
        first = next;
    } else {
        // 不是首节点,将被删除节点的前一个节点的下一个节点的引用,改为被删除的节点的下一个节点引用。
        prev.next = next;
        // 将被删除的节点前一个节点置空,至此前一个节点的引用调整完毕
        x.prev = null;
    }
    // 判断是被删除的节点,否为尾节点
    if (next == null) {
        // 是尾节点,将最尾节点的引用,改为被删除的节点的前一个节点的引用
        last = prev;
    } else {
        // 不是尾节点,将被删除的后一个节点的前一个节点的引用,改为被删除节点的前一个节点
        next.prev = prev;
        // 将被删除的节点后一个节点置空,至此后一个节点的引用调整完毕
        x.next = null;
    }
    // 将节点的值置空,至此全部引用置空
    x.item = null;
    // 集合数量减1
    size--;
    // 状态记录参数加1
    modCount++;
    // 返回被删除的节点的值
    return element;
}
2.重载的删除方法
/**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If this list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * {@code i} such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns {@code true} if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     *
     * @param o element to be removed from this list, if present
     * @return {@code true} if this list contained the specified element
       从此列表中删除第一次出现的指定元素,如果存在*,则将其删除。如果此列表不包含该元素,则*不变。更正式地,删除具有最低索引* {@code i}的元素,使* <tt>(o == null?get(i)== null:o.equals(get(i)))</ tt> *(如果存在这样的元素)。如果此列表*包含指定的元素(或者等效地,如果此列表*由于调用而更改),则返回{@code true}。 * * @param o要从此列表中删除的元素(如果存在)* @return {@code true}如果此列表包含指定的元素
     */
    public boolean remove(Object o) {
        // 判断值是否为Null,值为null节点不会为null
        if (o == null) {
            // 从首节点开始遍历,只删除一个等于null的元素,返回true
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            // 从首节点开始遍历,删除一个调用equals的值,取消其在整体链表中的链接返回true
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        // 没有找到返回False
        return false;
    }
contains
/**
 * Returns {@code true} if this list contains the specified element.
 * More formally, returns {@code true} if and only if this list contains
 * at least one element {@code e} such that
 * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
 *
 * @param o element whose presence in this list is to be tested
 * @return {@code true} if this list contains the specified element
   如果此列表包含指定的元素,则返回{@code true}。 
   *更正式地讲,当且仅当此列表包含*至少一个元素{@code e}时,才返回{@code true},使得
   * <tt>(o == null?e == null:o.equals(e) )</ tt>。 * 
   * @param o要在此列表中进行测试的元素* 
   @return {@code true}(如果此列表包含指定的元素)
 */
public boolean contains(Object o) {
    // 调用indexOf进行下标查询, 返回-1表示不存在。
    return indexOf(o) != -1;
}
indexOf
/**
 * Returns the index of the first occurrence of the specified element
 * in this list, or -1 if this list does not contain the element.
 * More formally, returns the lowest index {@code i} such that
 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
 * or -1 if there is no such index.
 *
 * @param o element to search for
 * @return the index of the first occurrence of the specified element in
 *         this list, or -1 if this list does not contain the element
   返回指定元素在此列表中首次出现的索引*,如果此列表不包含该元素,则返回-1。 
   *更正式地,返回最低索引{@code i},以便
   * <tt>(o == null?get(i)== null:o.equals(get(i)))</ tt>,
   *或如果没有这样的索引,则为-1。 * 
   * @param o要搜索的元素* 
   @返回此列表中指定元素的首次出现的索引;如果此列表不包含该元素,则返回-1
 */
public int indexOf(Object o) {
    // 保存循环过的次数,也就是 链表所谓的下标(索引)
    int index = 0;
    // 判断需要查询的数据是否为空,LinKedList允许存放重复的Null值
    if (o == null) {
        // 从首节点开始遍历 返回对应的下标
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null)
                return index;
            // 循环过的次数加1
            index++;
        }
    } else {
        //
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            // 循环过的次数加1
            index++;
        }
    }
    // 返回-1 不存在
    return -1;
}
size
/**
 * Returns the number of elements in this list.
 *
 * @return the number of elements in this list
 */
public int size() {
    // 直接返回内部属性
    return size;
}
clear
/**
 * Removes all of the elements from this list.
 * The list will be empty after this call returns.
   从此列表中删除所有元素。 *此调用返回后,列表将为空
 */
public void clear() {
    // Clearing all of the links between nodes is "unnecessary", but:
    // - helps a generational GC if the discarded nodes inhabit
    //   more than one generation
    // - is sure to free memory even if there is a reachable Iterator
    //清除节点之间的所有链接都是“不必要的”,但是:
    //-如果丢弃的节点驻留在多个代中,则有助于一代代GC 
    //-即使存在可达的迭代器,也要确保释放内存
    // 从首节点开始遍历清理
    for (Node<E> x = first; x != null; ) {
        // 先拿取到当前节点的下一个节点的引用
        Node<E> next = x.next;
        // 清空当前节点
        x.item = null;
        x.next = null;
        x.prev = null;
        // 重新赋值当前节点为清空的下一个节点,继续遍历
        x = next;
    }
    // 首尾节点全部置空
    first = last = null;
    // 集合大小置空
    size = 0;
    // 状态记录参数 +1 
    modCount++;
}
toArray
/**
 * Returns an array containing all of the elements in this list
 * in proper sequence (from first to last element).
 *
 * <p>The returned array will be "safe" in that no references to it are
 * maintained by this list.  (In other words, this method must allocate
 * a new array).  The caller is thus free to modify the returned array.
 *
 * <p>This method acts as bridge between array-based and collection-based
 * APIs.
 *
 * @return an array containing all of the elements in this list
 *         in proper sequence
   以正确的顺序(从第一个到最后一个元素)返回包含此列表*中所有元素的数组。 * * <p>返回的数组将是“安全的”,因为此列表不保留对其的引用。 (换句话说,此方法必须分配*一个新数组)。因此,调用者可以自由修改返回的数组。 * * <p>此方法充当基于数组的API和基于集合的API之间的桥梁。 * * @以正确的顺序返回包含此列表中所有元素的数组*
 */
public Object[] toArray() {
    // 创建一个可以接收链表中所有数据的数组
    Object[] result = new Object[size];
    // 数组下标
    int i = 0;
    // 从首节点快开始遍历赋值
    for (Node<E> x = first; x != null; x = x.next)
        result[i++] = x.item;
    return result;
}
// 当且仅当传入的参数T[] a能保存下链表的所有数据时,才会对其进行赋值。
public <T> T[] toArray(T[] a) {
    // 当传入的数组长度小于链表中的所有数据的数量(就是无法全部保存的情况)
    if (a.length < size)
        a = (T[])java.lang.reflect.Array.new
        Instance(
        a.getClass().getComponentType(), size);
    // T[] a数组能保存链表所有数据的情况
    int i = 0;
    // 循环遍历对传入的数组赋值
    Object[] result = a;
    for (Node<E> x = first; x != null; x = x.next)
        result[i++] = x.item;

    if (a.length > size)
        a[size] = null;

    return a;
}
addAll

总结

1.链表式数据结构,双向链表,保存了首尾节点,add方法,向链表末尾加入元素。,可以用来做一个后进先出的栈,里面有pop,push。pollLast,pollFirst等方法

2.get(index)方法采用链表切断,再判断index靠近尾节点还是首节点,进行循环到指定节点返回。

3.remove(index) 方法先调用get(index)方法实现,找出对应的节点,再将需要删除的节点,前后引用调整好,返回删除节点的值,最后将删除的节点的所有的属性置为null,remove(Object)讲道理要比remove(index)方法慢一倍(极端情况),因为remove(Object)方法没有切断链表,需要从首节点开始遍历删除。

4.contains(Object) 底层调用 indexOf(Object)从首节点遍历查询出第一个相等的元素索引,没有查询到返回-1.也就是不存在。

4.toArray方法手动创建一个数组,循环赋值,值类型的话改变数组对象对链表数据没影响,引用类型改变此数组的数据,链表中的数据也会随之改变。toArray (T[])最好是用返回值。传入的 t[] 当且仅当 t[] >= size(链表中元素数量) 时才会对 传入的 t[]数组进行赋值,返回值则无论哪种情况都是赋值好的全部底层数据。(还可以就是t[]数组的大小用链表的size来设置,这样t[]初始化就没问题)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值