JDK源码之LinkedList解析

java集合之LinkedList解析

LinkedList继承关系图

在这里插入图片描述

从继承图中我们可以看出LinkedList实现了List接口、Deque接口、Serializable接口、Cloneable接口

  • 实现了List接口,具备了List集合框架的基本功能,具备了基本的添加、删除、遍历等操作

  • 实现了Deque接口,具备了队列(双端队列)的基本功能

  • 实现了Serializable接口,具备了可序列化的功能

  • 实现了Cloneable接口,具备了克隆功能

LinkedList底层是由双向链表实现的,因为实现了Deque接口,所以也可以当做栈、队列、双端队列来使用

元素的存储结构

在LinkedList中的每一个结点并不是一个基本数据类型,而是一个Node对象,每个结点对象存储有三个变量,指向上一个Node对象的指针prev、当前结点存储元素的值item、指向下一个Node对象的指针next

 //这是Node类的定义,因为这是定义在LinkedList中的,所以这也是一个内部类
 private static class Node<E> {
        E item;               //这个结点的存储的元素值
        Node<E> next;         //指向下一个结点,只是个指针(引用),存储的是下一个结点的地址
        Node<E> prev;         //指向上一个结点,只是个指针(引用),存储的是上一个结点的地址
		//这里要注意区分存储的是下一个结点的地址和自己本身地址的区别
        //Node的构造函数,三个属性分别为:指向上一个结点的指针、当前结点存储的元素、指向下一个结点的指针
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
LinkedList的构造函数与成员变量
public LinkedList() {				//无参构造函数
    }


public LinkedList(Collection<? extends E> c) {		//传入一个序列的构造函数
        this();		//调用无参构造函数
        addAll(c);	//将序列添加到集合里
    }
    
transient int size = 0;				//集合中存储结点的个数

transient Node<E> first;			//集合的第一个结点

transient Node<E> last;				//集合的最后一个结点
LinkedList的成员方法
addAll方法

向集合中添加一个序列

	public boolean addAll(Collection<? extends E> c) {		//在索引为index处添加一个序列
        return addAll(size, c);
    }

    //将序列添加在下标为index处,原来在index处及之后的元素按原来的顺序放在添加序列的末尾
    public boolean addAll(int index, Collection<? extends E> c) {	//添加到集合的后面
    checkPositionIndex(index);      //检查下标是否合法(下标在0~size属于合法)

    Object[] a = c.toArray();       //将序列转化为数组
    int numNew = a.length;          //新添加序列的元素数量
    if (numNew == 0)                //如果数量为0,说明序列为空,返回false说明添加不成功
    	return false;

    Node<E> pred, succ;             //记录索引处的前驱结点和后继结点
    if (index == size) {            //index==size说明添加到末尾
    	succ = null;                //后继结点为空
        pred = last;                //前驱结点为last
        } else {                        //否则
        succ = node(index);         //后继结点为原来下标为index处的结点
        pred = succ.prev;           //前驱结点为原来下标为index处结点的前驱结点
        }

	for (Object o : a) {            //依次添加这个序列
    @SuppressWarnings("unchecked") E e = (E) o;
    //注意:每次添加结点时,不必更新结点的next,只需更新结点的pred(前驱结点的指针)和item(当前结点存储的元素)即可
    //为什么不用更新后继结点呢?因为在添加下一个结点时这个时候我们知道了下一个结点的地址再更新比较方便
    //最后一个结点单独处理一个它的next结点即可
    Node<E> newNode = new Node<>(pred, e, null);    //构造新结点,前驱结点为pred
    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;                 //更新集合中结点的数量
    modCount++;                     //集合操作次数
    return true;                    //添加成功,返回true
    }
node(int index)方法

**返回序号为index的结点

	Node<E> node(int index) {
        //断言index是集合的合法的下标。这个方法其实是被其他方法调用的,在其他方法中已经判断过下标是否合法了
        // assert isElementIndex(index);

        //下面有个小优化
        if (index < (size >> 1)) {      //index小于集合长度的一半,从前往后遍历
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {                        //index大于集合长度的一半,从后往前遍历
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
一些私有方法

下面介绍一些私有方法,LinkedList的许多方法都是由这些私有方法组合实现的

将一个方法私有化,类的对象是不能调用的,只有在类中才可以使用

linkFirst(E e)

在集合首部添加一个元素

	private void linkFirst(E e) {                       //在集合首部添加一个元素
            final Node<E> f = first;                    //用f变量将原来的首部存储起来
            final Node<E> newNode = new Node<>(null, e, f);     //new一个新结点
            first = newNode;                            //更新first
            if (f == null)                              //f为空说明原来的集合是空的,更新last
                last = newNode;
            else                                        //否则f的前驱结点就是newNode结点
                f.prev = newNode;
            size++;                                     //集合元素数量加1
            modCount++;                                 //集合修改次数加1
        }
linkLast(E e)

在集合尾部添加一个元素

	void linkLast(E e) {                            //在集合末尾添加一个元素
                final Node<E> l = last;                 //存储一下原来的末尾结点为l
                final Node<E> newNode = new Node<>(l, e, null); //new一个新结点
                last = newNode;                         //更新last结点  
                if (l == null)                          //如果l为null,说明原来集合为空,更新一下first
                    first = newNode;
                else
                    l.next = newNode;                   //否则,更新一下l的next
                size++;                                 //集合数量加1
                modCount++;                             //集合的修改次数加1
            }
linkBefore(E e, Node succ)

将元素e添加在succ结点之前

	void linkBefore(E e, Node<E> succ) {
        // assert succ != null;     断言结点不为空
        final Node<E> pred = succ.prev;     //存储succ前驱结点的指针
        final Node<E> newNode = new Node<>(pred, e, succ);  //new一个新结点
        succ.prev = newNode;                //更新succ的前驱结点为newNode接点
        if (pred == null)                   //如果前驱结点为null,说明当前结点为第一个结点,更新first为newNode结点
            first = newNode;
        else
            pred.next = newNode;            //否则,更新前驱结点的后继结点为newNode
        size++;                             //集合数量+1
        modCount++;                         //集合修改次数+1
    }
unlinkFirst(Node f)

删除首部结点

	private E unlinkFirst(Node<E> f) {
                 //断言f为首部结点并且f(首部)不为空
                 // assert f == first && f != null;
                 final E element = f.item;      //获取首部结点的值
                 final Node<E> next = f.next;   //记录首部的后继结点
                 f.item = null;                 //将首部存储元素的变量置为null,方便垃圾回收
                 f.next = null; // help GC
                 first = next;                  //更新首部结点
                 if (next == null)              //如果后继结点为null,说明集合原来只有一个结点
                     last = null;
                 else
                     next.prev = null;          //否则更新新的首部的前驱结点
                 size--;                        //集合数量加1
                 modCount++;                    //集合修改次数加1
                 return element;                //返回删除前的首部结点的值
             }
unlinkLast(Node e)

删除尾部结点

		//删除尾部结点的值
         private E unlinkLast(Node<E> l) {      
                 //断言结点l是尾部结点并且尾部结点非空
                 // assert 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--;                            //集合数量-1  
                 modCount++;                        //集合修改次数+1
                 return element;                    //返回修改前的尾部结点存储的元素值
             }
unlink(Node x)

删除某个结点

 		//删除某个结点
         E unlink(Node<E> x) {
                 // assert x != null;
                 //断言结点x非空
                 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;                     //将存储删除结点元素值的变量置空,方便垃圾回收
                 size--;                            //集合中元素数量-1
                 modCount++;                        //集合修改次数+1
                 return element;                    //返回删除结点的元素值
             }
isElementIndex(inde index)
		//检查索引是否合法
        private boolean isElementIndex(int index) {
                return index >= 0 && index < size;
            }
isPositionIndex(int index)
		//检查索引是否合法
        private boolean isPositionIndex(int index) {
                return index >= 0 && index <= size;
            }
一些对象可以调用的方法

这些对象可以调用的方法很多都是调用上面的私有方法结合一些逻辑组合而成的

add(E e)

将元素添加到集合的末尾

		//添加元素到集合的末尾
         public boolean add(E e) {
                 linkLast(e);           //调用linkFirst方法
                 return true;
             }
add(int index, E e)

在下标为index处添加元素

 		//将集合添加到下标为index处
         public void add(int index, E element) {
                 checkPositionIndex(index);     //检查下表是否合法

                 if (index == size)             //添加到尾部,调用linkLst方法
                     linkLast(element);
                 else                           //添加到index处
                     linkBefore(element, node(index));//linkBefore这个方法穿进去的index索引必须在0~size-1之间
             }
addFirst(E e)

在集合首部添加一个元素

		//在集合首部添加一个元素
         public void addFirst(E e) {
                 linkFirst(e);      //调用linkFirst方法
             }
addLast(E e)

在集合尾部添加一个元素

		//在集合尾部添加一个元素     
        public void addLast(E e) {
                linkLast(e);        //调用linkLast方法
            }
removeFirst()

删除首部结点

		//删除首部结点
        public E removeFirst() {
                final Node<E> f = first;
                if (f == null)
                    throw new NoSuchElementException();
                return unlinkFirst(f);      //调用unlinkFirst
            }
removeLast()

删除尾部结点

		//删除尾部结点
        public E removeLast() {
                final Node<E> l = last;
                if (l == null)
                    throw new NoSuchElementException();
                return unlinkLast(l);       //调用UnlinkLast方法
            }

remove(Object 0)

删除集合中元素为o的结点

		//删除集合中元素值为o的结点    
        public boolean remove(Object o) {
                //下面内容大意就是先顺序遍历找到第一个结点存储的元素值等于o的结点,接着调用unlink(Node<E> e)删除结点
                //删除成功返回true,删除失败返回false(集合中存储该元素值的结点)
                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) {
                        if (o.equals(x.item)) {
                            unlink(x);  
                            return true;
                        }
                    }
                }
                return false;
            }
remove(int index)

删除下标为index的结点

		//删除下标为index的结点
        public E remove(int index) {
                checkElementIndex(index);		//检查索引是否合法
                return unlink(node(index));		//调用node(index)找到结点,接着调用unlink(Node<E> e)删除
            }
set(int index, E element)

修改下标为index结点处存储的元素值

		//修改下标为index的结点存储的元素值
        public E set(int index, E element) {
                checkElementIndex(index);
                Node<E> x = node(index);    //调用node(index)找到下标为index索引的结点,接着修改结点的值值
                E oldVal = x.item;
                x.item = element;
                return oldVal;              //返回修改前结点存储的元素的值
            }
get(int index)

返回下标为index处结点存储的元素值

		//返回下标为index的结点存储的元素值
        public E get(int index) {
                checkElementIndex(index);   //检查索引是否合法
                return node(index).item;    //调用node(index)找到结点,之后返回结点存储的元素
            }
getFirst()

返回集合首结点存储元素的值

		//返回集合的首结点的元素的值
        public E getFirst() {
                final Node<E> f = first;    //直接将首结点赋给f
                if (f == null)              //检查首结点是否为空
                    throw new NoSuchElementException();
                return f.item;              //返回首结点存储元素的值
            }   
getLast()

返回集合尾结点的值

		//返回集合尾结点的元素值
        public E getLast() {
                final Node<E> l = last;     //直接将last赋值给l
                if (l == null)              //检查尾结点是否非空
                    throw new NoSuchElementException();
                return l.item;
            }
indexOf(Object o)

返回元素o的下标(从前往后遍历)

		//返回集合中结点存储的元素的值为o的下标
        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;
            }
lastIndexOf(Object o)

返回结点元素值等于o的下标(从后往前遍历)

	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;
    }
LinkedList中的迭代器
//在LinkedList中的迭代器是一个双向迭代器,支持向前和向后的迭代
        private class ListItr implements ListIterator<E> {
                private Node<E> lastReturned;       //上一次next()方法返回的结点
                private Node<E> next;               //下一个结点
                private int nextIndex;              //下一个结点的索引
                private int expectedModCount = modCount;    //检查在迭代期间是否通过非迭代器的方法修改了数组结构

                ListItr(int index) {
                    // assert isPositionIndex(index);
                    next = (index == size) ? null : node(index);
                    nextIndex = index;
                }

                public boolean hasNext() {          //检查是否还有下一个元素,只需要判断下一个结点的索引是否小于size即可
                    return nextIndex < size;
                }

                public E next() {					//返回下一个结点存储的的元素值
                    checkForComodification();
                    if (!hasNext())
                        throw new NoSuchElementException();

                    lastReturned = next;			//更新lastReturned
                    next = next.next;				//更新next
                    nextIndex++;					//下一个结点的index+1
                    return lastReturned.item;		//返回目标结点实际存储的元素的值
                }

                public boolean hasPrevious() {		//判断是否还有上一个结点,只要下标不是0就行(首结点)
                    return nextIndex > 0;
                }

                public E previous() {				//返回上一个结点
                    checkForComodification();
                    if (!hasPrevious())
                        throw new NoSuchElementException();
					//从尾到头遍历时,第一次执行此方法将last赋给lastReturned
                    lastReturned = next = (next == null) ? last : next.prev;	//更新上一个结点
                    nextIndex--;
                    return lastReturned.item;
                }

                public int nextIndex() {		//返回下一个结点的下标
                    return nextIndex;
                }

                public int previousIndex() {	//返回上一个结点(实际为next结点的前驱结点)的下标
                    return nextIndex - 1;
                }

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

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

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

注意:

LinkedList中的迭代器是ListIterator,获取时采用调用ListIterator对象的listIterator()方法

虽然ListIterator支持反向遍历,但是必须在先向遍历过一遍之后才能反向遍历,这个可以从源码ListIterator中看出

虽然LinkedList实现了ListIterator支持正向遍历、反向遍历的迭代器,但是仍然实现了只支持正向遍历的Iterator接口,使用Iterator接收,调用iterator()返回迭代器

//代码如下
//ListIterator迭代器
LinkedList<String> list = new LinkedList<>();
        list.add("1111");
        list.add("222");
        list.add("3333");
        System.out.println(list.size());
        ListIterator iterator = list.listIterator();
        //iterator.
        while(iterator.hasNext())
        {
            System.out.println(iterator.next());
        }
        while(iterator.hasPrevious())
        {
            System.out.println(iterator.previous());
        }
//Iterator迭代器
LinkedList<String> list = new LinkedList<>();
        list.add("1111");
        list.add("222");
        list.add("3333");
        System.out.println(list.size());
        Iterator iterator = list.iterator();
        //iterator.
        while(iterator.hasNext())
        {
            System.out.println(iterator.next());
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值