JDK 1.8 LinkedList源码解析

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

关于AbstractSequentialList这个类的源码可以参考:https://mp.csdn.net/postedit/88303467

List接口想必不用多说,Collection集合下的一个分支。

Deque 详请参考:https://www.cnblogs.com/bushi/p/6681543.html

下面将代码前大家一定要清除LinkedList是一个链表!!!,所以的操作都是建立在该数据结构之上定义的

transient int size = 0;

记录当前集合的长度

transient Node<E> first;

指向第一个节点的指针。

  transient Node<E> last;

指向最后一个节点的指针

 public LinkedList() {
 }

构造一个空的链表

public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
}

构造一个包含指定元素的列表

private void linkFirst(E e) {
        //指向头节点
        final Node<E> f = first;
        //该新构造的节点无前驱,后继为f
        final Node<E> newNode = new Node<>(null, e, f);
        //第一个节点的指针设为 newNode
        first = newNode;
        //如果f为空 代表修改前该链表还是一个空链表
        if (f == null)
            //那么最后一个节点的指针也指向newNode
            last = newNode;
        else
            f.prev = newNode;
        size++;
        //modCount 记录了当前链表的修改次数,这和LinkedList非线程安全有关
        modCount++;
}

链接e作为第一个元素。

void linkLast(E e) {
        final Node<E> l = last;
        //该新节点的前驱为 l 无后继
        final Node<E> newNode = new Node<>(l, e, null);
        //最后一个节点的指针设为 newNode
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
}

和上面的相反 即 链接e作为最后一个元素。

 void linkBefore(E e, Node<E> succ) {
        //断言succ != null; pred 为succ的前驱
        final Node<E> pred = succ.prev;
        //新节点的前驱为pred 后继为succ 内容为e
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
}

在非null节点succ之前插入元素e,succ不能为null该方法并为做空值处理

注意:传入的参数都符合断言的要求,因为这是一个内部方法,及不对开发者公开。

private E unlinkFirst(Node<E> f) {
        //断言 f == first && f != null;
        final E element = f.item;//f.item 即该节点的内容(即:元素)
        final Node<E> next = f.next;
        // = null 的原因是好让GC回收
        f.item = null;
        f.next = null; 
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
}

也就是放弃连接第一个节点,让第一个节点的后继节点成为该链表的first。注意:穿过来的f参数必定是第一个节点

 private E unlinkLast(Node<E> l) {
        //断言 l == last && l != null;
        final E element = l.item;
        final Node<E> prev = l.prev;
        l.item = null;
        l.prev = null; // help GC
        last = prev;
        if (prev == null)
            first = null;
        else
            prev.next = null;
        size--;
        modCount++;
        return element;
}

 

和上面哪个方法刚好相反及取消链接非空的最后一个节点l。

 E unlink(Node<E> x) {
        // 断言 x != null;
        final E element = x.item;
        //获取x的前驱后继
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;
        //如果 prev 为空那么代表着x为第一个节点,所以就指向改变first指向为next即可
        if (prev == null) {
            first = next;
        } else {
            //绕过x,将x的前驱的后继改为next
            prev.next = next;
            x.prev = null;
        }
        //如果next为空,代表x无后继,也就是x是last节点,所以直接将last指向改为prev即可
        if (next == null) {
            last = prev;
        } else {
            //绕过 x节点,将next的前驱改为prev
            next.prev = prev;
            x.next = null;
        }
        
        x.item = null;
        size--;
        modCount++;
        return element;
}

取消链接非空节点x。就是将x节点从该链表中移除掉。

public E getFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
}

返回此列表中的第一个元素。

 public E getLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return l.item;
}

返回此列表中的最后一个元素。

public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
}

移除该链表的第一个元素

public E removeLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
}

移除该链表的最后一个元素

public void addFirst(E e) {
        linkFirst(e);
}

在此列表的开头插入指定的元素

 public void addLast(E e) {
        linkLast(e);
 }

在此列表的结尾插入指定的元素

public boolean contains(Object o) {
        return indexOf(o) != -1;
}

判断是否包含给定元素

public int size() {
        return size;
}

返回当前列表长度

 public boolean add(E e) {
        linkLast(e);
        return true;
 }

将指定的元素追加到此列表的末尾

public boolean remove(Object o) {
        //判断o是否为null 防止空指针异常
        if (o == null) {
            //从链表的开始位置遍历整个链表,直达找为该元素或者遍历完整个链表为停止
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    //移除该元素
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                //这就是为什么要做非空判断并且弄两个循环变了的原因了(即:null.equals(x.item)报错)
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        //return false 代表没找到
        return false;
    }

如果该集合包含给定元素,就移除掉

//index为插入当前集合的位置,c为要将所以元素都插入的哪个集合
    public boolean addAll(int index, Collection<? extends E> c) {
        //判断索引是否溢出当前集合
        checkPositionIndex(index);
        //将c转为数组赋值给 a
        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred,//pred为要插入节点位置的前驱节点
                succ;//succ为要插入的节点位置
        //如果index == size 代表要在最后插入
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }
        //遍历a数组
        for (Object o : a) {
            @SuppressWarnings("unchecked")
            //类型强转
            E e = (E) o;
            //实例化节点,节点的前驱为 pred 无后继
            Node<E> newNode = new Node<>(pred, e, null);
            //如果pred为null代表无当前节点所在位置为表头
            if (pred == null)
                first = newNode;
            else
                //把节点间链接起来
                pred.next = newNode;
            //pred不断移动
            pred = newNode;
        }
        //如果succ为null则代表插入的位置是链表的末尾
        if (succ == null) {
            last = pred;
        } else {
            //如果succ不为null则代表在链表间插入,那么我们就把它重新串联起来
            pred.next = succ;
            succ.prev = pred;
        }
        
        size += numNew;
        modCount++;
        return true;
}

间集合c中的所有元素从指定位置index处统统添加进该链表中

 public void clear() {
        //从表头遍历到表尾 将节点的属性设置为null 让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;
        modCount++;
}

清空链表

 private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
 }

判断参数是否是现有元素的索引。

private boolean isPositionIndex(int index) {
       return index >= 0 && index <= size;
}

判断参数是否是迭代器或添加操作的有效位置的索引。

Node<E> node(int index) {
        // 断言 index为合法索引
        
        //翻译: index < (size / 2) 从中可以看出做了算法优化
        if (index < (size >> 1)) {
            Node<E> x = first;
            //从first节点不断调用next方法来得到指定位置的节点
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            //从last节点不断调用prev方法来得到指定位置的节点
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
}

返回指定位置上的节点

public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
}

返回该对象在链表中第一次出现的位置索引

//和indexOf套路相同,只不过是讲next该为prev而已,就是倒着来
 public int lastIndexOf(Object o) {
        int index = size;
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (x.item == null)
                    return index;
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (o.equals(x.item))
                    return index;
            }
        }
        return -1;
}

返回该对象在链表中最后一次出现的位置索引

public E poll() {
        final Node<E> f = first;
        //unlinkFirst方法即:取消链接非空的第一个节点f。
        return (f == null) ? null : unlinkFirst(f);
}

 检索并删除此列表的头部(第一个元素)

 public boolean removeLastOccurrence(Object o) {
        //只不过是从后往前遍历
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
 }

删除此列表中最后一次出现的指定元素。如果列表不包含该元素,则不会更改。

 public Object clone() {
        LinkedList<E> clone = superClone();

        // Put clone into "virgin" state
        clone.first = clone.last = null;
        clone.size = 0;
        clone.modCount = 0;

        // 使用我们的元素初始化克隆
        for (Node<E> x = first; x != null; x = x.next)
            clone.add(x.item);

        return clone;
}

从新定义了clone方法

 private static final long serialVersionUID = 876323262645176354L;

该值和序列化有关详请参考:https://www.cnblogs.com/zheting/p/7751949.html

 

 

内部类

ListIter迭代器

//实现了ListIterator 该接口比ListIter更灵活
private class ListItr implements ListIterator<E> {
    //光标当前所在节点
    private Node<E> lastReturned;
    //
    private Node<E> next;
    //代表next节点在链表中的索引
    private int nextIndex;
    //这样定义是因为该类非线程安全的缘故
    private int expectedModCount = modCount;
    //指定光标位置构造迭代器
    ListItr(int index) {
        //断言 Index必定是合法索引
        next = (index == size) ? null : node(index);
        nextIndex = index;
    }
    //是否还能调用next返回下一位对象
    public boolean hasNext() {
        return nextIndex < size;
    }
    //移动光标并返回下一位元素
    public E next() {
        checkForComodification();
        if (!hasNext())
            throw new NoSuchElementException();

        lastReturned = next;
        next = next.next;
        nextIndex++;
        //返回该节点内的元素
        return lastReturned.item;
    }
    //是否还能向上移动光标位置
    public boolean hasPrevious() {
        return nextIndex > 0;
    }
    //返回列表中的上一个元素,并向后移动光标位置。
    public E previous() {
        checkForComodification();
        if (!hasPrevious())
            throw new NoSuchElementException();

        lastReturned = next = (next == null) ? last : next.prev;
        nextIndex--;
        return lastReturned.item;
    }
    //返回随后调用 next()返回的元素的索引。
    public int nextIndex() {
        return nextIndex;
    }
    //返回由后续调用 previous()返回的元素的索引。
    public int previousIndex() {
        return nextIndex - 1;
    }
    //从列表中删除由 next()或 previous()返回的最后一个元素(可选操作)。
    public void remove() {
        checkForComodification();
        if (lastReturned == null)
            throw new IllegalStateException();

        Node<E> lastNext = lastReturned.next;
        unlink(lastReturned);
        if (next == lastReturned)
            next = lastNext;
        else
            nextIndex--;
        lastReturned = null;
        expectedModCount++;
    }
    //用 指定的元素替换由 next()或 previous()返回的最后一个元素(可选操作)。
    public void set(E e) {
        if (lastReturned == null)
            throw new IllegalStateException();
        checkForComodification();
        lastReturned.item = e;
    }

    //将指定的元素插入列表(可选操作)。
    public void add(E e) {
        checkForComodification();
        lastReturned = null;
        if (next == null)
            linkLast(e);
        else
            linkBefore(e, next);
        nextIndex++;
        expectedModCount++;
    }
    //该方法是JDK 1.8新增的 用于支持Lamdba表达式
    //详请查看:https://blog.csdn.net/qq_37465638/article/details/83068283
    public void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        //从当前位置迭代每一位
        while (modCount == expectedModCount && nextIndex < size) {
            action.accept(next.item);
            lastReturned = next;
            next = next.next;
            nextIndex++;
        }
        checkForComodification();
    }
    //防止多线程篡改,由于该类是非线程安全的缘故
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

节点(链表实现密不可分的一个内部类)

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

降序迭代器

public Iterator<E> descendingIterator() {
        return new DescendingIterator();
}

就是倒着迭代,我们看看DescendingIterator这个类的实现:

  private class DescendingIterator implements Iterator<E> {
        //获得当前对象的ListItr迭代器,光标位置在当前链表的末尾。用于从后往前迭代
        private final ListItr itr = new ListItr(size());
        //哈哈,其实有点像阳奉阴违
        public boolean hasNext() {
            return itr.hasPrevious();
        }
        public E next() {
            return itr.previous();
        }
        public void remove() {
            itr.remove();
        }
    }

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值