当前位置: 首页 > news >正文

Java集合源码分析之LinkedList

一、LinkedList结构

 

  LinkedList是一种可以在任何位置进行高效地插入和移除操作的有序序列,它是基于双向链表实现的。
  LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
  LinkedList 实现 List 接口,能对它进行队列操作。
  LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
  LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
  LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
  LinkedList 是非同步的。

二、源码说明

  1.LikedList属性

    //LinkedList的属性非常简单,一个头结点、一个尾结点、一个表示链表中实际元素个数的变量。
    //注意,头结点、尾结点都有transient关键字修饰,这也意味着在序列化时该域是不会序列化的。
    //元素个数    
    transient int size = 0;
    //头结点
    transient Node<E> first;
    //尾节点    
    transient Node<E> last;

  2.构造函数

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

  LinkedList没有长度的概念,所以不存在容量不足的问题,因此不需要提供初始化大小的构造方法,因此只提供了两个方法,一个是无参构造方法,初始一个LinkedList对象,一个是将指定的集合元素转化为LinkedList构造方法。

  3.添加方法 add()

    public boolean add(E e) {
     linkLast(e);
     return true;
    }
    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++;
    }

  添加方法默认是添加到LinkedList的尾部,首先将last指定的节点赋值给l节点,然后新建节点newNode ,此节点的前驱指向l节点,data = e , next = null , 并将新节点赋值给last节点,它成为了最后一个节点,根据当前List是否为空做出相应的操作。若不为空将l的后继指针修改为newNodw。 size +1 , modCount+1

   4.删除方法

    public boolean remove(Object o) {
        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;
    }

  删除方法,先循环遍历列表,找到item == o 的节点,在调用unlink()方法删除

  5.查询 get(index)

    //获取指定位置的元素
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    //返回指定位置的节点信息,
    //LikedList无法随机访问,只能通过遍历的方式找到相应的结点
    //为了提高效率,当前位置首先和元素的中间位置开始判断,小于中间位置
    //从头结点开始遍历,大于中间位置从尾结点开始遍历
    Node<E> node(int index) {
        // assert isElementIndex(index);
        if (index < (size >> 1)) {
            Node<E> x = first;
            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;
        }
    }

三、内部类介绍

  在LinkedList中除了有一个Node的内部类外,应该还能看到另外两个内部类,那就是ListItr,还有一个是DescendingIterator。

  1.ListItr内部类

  

   

  •     看到方法名之后,就发现不止有向后迭代的方法,还有向前迭代的方法,所以我们就知道了这个ListItr这个内部类干嘛用的了,就是能让linkedList不光能像后迭代,也能向前迭代。
  •     看一下ListItr中的方法,可以发现,在迭代的过程中,还能移除、修改、添加值得操作。

   2.DescendingIterator内部类

    //看一下这个类,还是调用的ListItr,作用是封装一下Itr中几个方法,让使用者以正常的思维去写代码,例如,在从后往前遍历的时候,
   //也是跟从前往后遍历一样,使用next等操作,而不用使用特殊的previous。
private class DescendingIterator implements Iterator<E> { 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. LinkedList是一个功能很强大的类,可以被当作List集合,双端队列和栈来使用。linkedList本质上是一个双向链表,通过一个Node内部类实现的这种链表结构。
  2. 能存储null值,在查找和删除某元素时,源码中都划分为该元素为null和不为null两种情况来处理,LinkedList中允许元素为null。
  3. 在实现的接口中,应该注意到没有RandomAccess:那么就推荐使用iterator,在其中就有一个foreach,增强的for循环,其中原理也就是iterator,我们在使用的时候,使用foreach或者iterator都可以。
  4. LikedList是顺序存取结构(注意和随机存取结构两个概念搞清楚)
  5. LinkedList在1.8版本有添加了一点新的内容,添加了一个static final 修饰的内部类LLSpliterator 并实现了Spliterator ,
  6. LinkedList底层使用链表来保存集合中的元素,因此随机访问的性能较差,但是插入删除时性能非常的出色。

 

 

参考

   https://www.cnblogs.com/zhangyinhua/p/7688304.html

      https://my.oschina.net/90888/blog/1625505

转载于:https://www.cnblogs.com/ZeGod/p/10010351.html

相关文章:

  • 消息总线重构之EventBus
  • XLSReadWriteII5导入excel数据
  • 记录:Spring JdbcTemplate查询返回的Map与数据库对查询字段名的处理
  • 【转载】SSH服务器端/etc/ssh/sshd_conf配置文件详解
  • 微软私有云分享(R2)23 裸金属安装
  • 竞赛题解 - CF Round #524 Div.2
  • MySQL数据“误”删“攻防”战
  • 2018年OpenStack用户调查报告出炉:Kubernetes仍居首
  • Entity相互关系
  • 记一次程序员在办公室里的“撕逼”经历
  • Oracle常用的数值函数,日期函数
  • mac flutter 环境搭建
  • Centos6.6升级Python与安装ipython、pip小结
  • DVWA SQL Injection LOW
  • Apache用户认证;域名跳转;Apache访问日志
  • C# 免费离线人脸识别 2.0 Demo
  • CentOS 7 防火墙操作
  • CSS中外联样式表代表的含义
  • exports和module.exports
  • vue-loader 源码解析系列之 selector
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 对象引论
  • 机器学习中为什么要做归一化normalization
  • 记一次删除Git记录中的大文件的过程
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 小李飞刀:SQL题目刷起来!
  • 自动记录MySQL慢查询快照脚本
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 阿里云服务器如何修改远程端口?
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • ​水经微图Web1.5.0版即将上线
  • #预处理和函数的对比以及条件编译
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (ZT)出版业改革:该死的死,该生的生
  • (备忘)Java Map 遍历
  • (分布式缓存)Redis持久化
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (四)Linux Shell编程——输入输出重定向
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • ./configure,make,make install的作用
  • .net core 6 集成和使用 mongodb
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .NET Core引入性能分析引导优化
  • .net 发送邮件
  • .NET程序员迈向卓越的必由之路
  • .NET企业级应用架构设计系列之结尾篇
  • .NET下ASPX编程的几个小问题
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • .sh 的运行
  • /usr/bin/env: node: No such file or directory
  • ??javascript里的变量问题