java linkedlist 节点_JAVA学习-LinkedList详解

article/2025/9/11 1:07:35

1.定义

实现List接口与Deque接口双向链表,实现了列表的所有操作,并且允许包括null值的所有元素,对于LinkedList定义我产生了如下疑问:

1.Deque接口是什么,定义了一个怎样的规范?

2.LinkedList是双向链表,其底层实现是怎样的,具体包含哪些操作?

下文将围绕这两个问题进行,去探寻LinkedList内部的奥秘,以下源码是基于JDK 1.7.0_79

2.结构

2.1 类结构

LinkedList的类的结构如下图所示

732b5294a985

image

通过上图可以看出,LinkedList继承的类与实现的接口如下:

1.Collection 接口: Collection接口是所有集合类的根节点,Collection表示一种规则,所有实现了Collection接口的类遵循这种规则

2.List 接口: List是Collection的子接口,它是一个元素有序(按照插入的顺序维护元素顺序)、可重复、可以为null的集合

3.AbstractCollection 类: Collection接口的骨架实现类,最小化实现了Collection接口所需要实现的工作量

4.AbstractList 类: List接口的骨架实现类,最小化实现了List接口所需要实现的工作量

5.Cloneable 接口: 实现了该接口的类可以显示的调用Object.clone()方法,合法的对该类实例进行字段复制,如果没有实现Cloneable接口的实例上调用Obejct.clone()方法,会抛出CloneNotSupportException异常。正常情况下,实现了Cloneable接口的类会以公共方法重写Object.clone()

6.Serializable 接口: 实现了该接口标示了类可以被序列化和反序列化,具体的 查询序列化详解

7.Deque 接口: Deque定义了一个线性Collection,支持在两端插入和删除元素,Deque实际是“double ended queue(双端队列)”的简称,大多数Deque接口的实现都不会限制元素的数量,但是这个队列既支持有容量限制的实现,也支持没有容量限制的实现,比如LinkedList就是有容量限制的实现,其最大的容量为Integer.MAX_VALUE

8.AbstractSequentialList 类: 提供了List接口的骨干实现,最大限度地减少了实现受“连续访问”数据存储(如链表)支持的此接口所需的工作,对于随机访问数据(如数组),应该优先使用 AbstractList,而不是使用AbstractSequentailList类

2.2 基础属性及构造方法

2.2.1 基础属性

public class LinkedList

extends AbstractSequentialList

implements List, Deque, Cloneable, java.io.Serializable

{

//长度

transient int size = 0;

//指向头结点

transient Node first;

//指向尾结点

transient Node last;

}

如上源码中为LinkedList中的基本属性,其中size为LinkedList的长度,first为指向头结点,last指向尾结点,Node为LinkedList的一个私有内部类,其定义如下,即定义了item(元素),next(指向后一个元素的指针),prev(指向前一个元素的指针)

private static class Node {

//元素

E item;

//指向后一个元素的指针

Node next;

//指向前一个元素的指针

Node prev;

Node(Node prev, E element, Node next) {

this.item = element;

this.next = next;

this.prev = prev;

}

}

那么假如LinkedList中的元素为["A","B","C"],其内部的结构如下图所示

732b5294a985

image

可以看出一个节点中包含三个属性,也就是上面源码中定义的属性,可以清晰的看出LinkedList底层是双向链表的实现

2.2.2构造方法

在源码中,LinkedList主要提供了两个构造方法,

1.public LinkedList() :空的构造方法,啥事情都没有做

2.public LinkedList(Collection extends E> c) : 将一个元素集合添加到LinkedList中

3.底层实现

在2.2.1中的LinkedList内部结构图,可以清晰的看出LinkedList双向链表的实现,下面将通过源码分析如何在双向链表中添加和删除节点的。

3.1 添加节点

通常我们会使用add(E e)方法添加元素,通过源码我们发现add(E e)内部主要调用了以下方法

//在链表的最后添加元素

void linkLast(E e) {

final Node l = last;

final Node newNode = new Node<>(l, e, null);

last = newNode;

if (l == null)

first = newNode;

else

l.next = newNode;

size++;

modCount++;

}

其实通过源码可以看出添加的过程如下:

1.记录当前末尾节点,通过构造另外一个指向末尾节点的指针l

2.产生新的节点:注意的是由于是添加在链表的末尾,next是为null的

3.last指向新的节点

4.这里有个判断,我的理解是判断是否为第一个元素(当l==null时,表示链表中是没有节点的),

那么就很好理解这个判断了,如果是第一节点,则使用first指向这个节点,若不是则当前节点的next指向新增的节点

5.size增加

例如,在上面提到的LinkedList["A","B","C"]中添加元素“D”,过程大致如图所示

732b5294a985

image

LinkedList中还提供如下的方法,进行添加元素,具体逻辑与linkLast方法大同小异,就不在这里一一介绍了。

3.2 删除节点

LinkedList中提供了两个方法删除节点,如下源码所示

//方法1.删除指定索引上的节点

public E remove(int index) {

//检查索引是否正确

checkElementIndex(index);

//这里分为两步,第一通过索引定位到节点,第二删除节点

return unlink(node(index));

}

//方法2.删除指定值的节点

public boolean remove(Object o) {

//判断删除的元素是否为null

if (o == null) {

//若是null遍历删除

for (Node x = first; x != null; x = x.next) {

if (x.item == null) {

unlink(x);

return true;

}

}

} else {

//若不是遍历删除

for (Node x = first; x != null; x = x.next) {

if (o.equals(x.item)) {

unlink(x);

return true;

}

}

}

return false;

}

通过源码可以看出两个方法都是通过unlink()删除,在方法一种有个方法要介绍下,就是node(index)该方法的作用就是根据下标找到对应的节点,要是本人去写这个方法肯定是遍历到index找到对应的节点,而JDK提供的方法如下所示

1.首先确定index的位置,是靠近first还是靠近last

2.若靠近first则从头开始查询,否则从尾部开始查询,可以看出这样避免极端情况的发生,也更好的利用了LinkedList双向链表的特征

Node node(int index) {

// assert isElementIndex(index);

if (index < (size >> 1)) {

Node x = first;

for (int i = 0; i < index; i++)

x = x.next;

return x;

} else {

Node x = last;

for (int i = size - 1; i > index; i--)

x = x.prev;

return x;

}

}

下面会详细介绍unlink()方法的源码,这是删除节点最核心的方法

E unlink(Node x) {

// assert x != null;

final E element = x.item;

final Node next = x.next;

final Node prev = x.prev;

//删除的是第一个节点,first向后移动

if (prev == null) {

first = next;

} else {

prev.next = next;

x.prev = null;

}

//删除的是最后一个节点,last向前移

if (next == null) {

last = prev;

} else {

next.prev = prev;

x.next = null;

}

x.item = null;

size--;

modCount++;

return element;

}

1.获取到需要删除元素当前的值,指向它前一个节点的引用,以及指向它后一个节点的引用。

2.判断删除的是否为第一个节点,若是则first向后移动,若不是则将当前节点的前一个节点next指向当前节点的后一个节点

3.判断删除的是否为最后一个节点,若是则last向前移动,若不是则将当前节点的后一个节点的prev指向当前节点的前一个节点

4.将当前节点的值置为null

5.size减少并返回删除节点的值

至此介绍了LinkedList添加、删除元素的内部实现。

4.对比

在ArrList详解中讲解了ArrayList的相关的内容,下面将对ArrayList与LinkedList进行对比,主要从以下方面进行

4.1 相同点

1.接口实现:都实现了List接口,都是线性列表的实现

2.线程安全:都是线程不安全的

4.2 区别

1.底层实现:ArrayList内部是数组实现,而LinkedList内部实现是双向链表结构

2.接口实现:ArrayList实现了RandomAccess可以支持随机元素访问,而LinkedList实现了Deque可以当做队列使用

3.性能:新增、删除元素时ArrayList需要使用到拷贝原数组,而LinkedList只需移动指针,查找元素 ArrayList支持随机元素访问,而LinkedList只能一个节点的去遍历

4.3 性能比较

下面通过代码去比较下ArrayList与LinkedList在性能方面的差别,代码如下

public class ListPerformance {

private static ArrayList arrayList= new ArrayList();

private static LinkedList linkedList = new LinkedList();

/**

* 插入数据

* @param list

* @param count

*/

public static void insertElements(List list, int count){

Long startTime = System.currentTimeMillis();

for (int i = 0; i < count; i++) {

list.add(String.valueOf(i));

}

Long endTime = System.currentTimeMillis();

System.out.println("insert elements use time: " +(endTime-startTime) + " ms");

}

/**

* 删除元素

* @param list

* @param count

*/

public static void removeElements(List list, int count){

Long startTime = System.currentTimeMillis();

for (int i = 0; i < count; i++) {

list.remove(0);

}

Long endTime = System.currentTimeMillis();

System.out.println("remove elements use time: " +(endTime-startTime) + " ms");

}

/**

* 获取元素

* @param list

* @param count

*/

public static void getElements(List list, int count){

Long startTime = System.currentTimeMillis();

for (int i = 0; i < count; i++) {

list.get(i);

}

Long endTime = System.currentTimeMillis();

System.out.println("get elements use time: " +(endTime-startTime) + " ms");

}

/**

* 删除元素第二种实现

* @param list

* @param count

*/

public static void removeElements2(List list, int count){

Long startTime = System.currentTimeMillis();

for (int i = count-1; i > 0; i--) {

list.remove(i);

}

Long endTime = System.currentTimeMillis();

System.out.println("remove elements use time: " +(endTime-startTime) + " ms");

}

public static void main(String[] args){

System.out.println("arrayList test");

insertElements(arrayList,100000);

getElements(arrayList,100000);

removeElements(arrayList,100000);

System.out.println("linkedList test");

insertElements(linkedList,100000);

getElements(linkedList,100000);

removeElements(linkedList,100000);

System.out.println("arrayList test2");

insertElements(arrayList,100000);

getElements(arrayList,100000);

removeElements2(arrayList,100000);

System.out.println("linkedList test2");

insertElements(linkedList,100000);

getElements(linkedList,100000);

removeElements2(linkedList,100000);

}

结果如下图所示,可以看出

732b5294a985

image

1.LinkedList下插入、删除是性能优于ArrayList,这是由于插入、删除元素时ArrayList中需要额外的开销去移动、拷贝元素(但是使用removeElements2方法所示去遍历删除是速度异常的快,这种方式的做法是从末尾开始删除,不存在移动、拷贝元素,从而速度非常快)

2.ArrayList在查询元素的性能上要由于LinkedList

5.总结

本文主要介绍了LinkedList的内部实现,主要从添加元素、删除元素入手分析LinkedList实现的细节,后面也将LinkedList与ArrayList进行了对比。


http://chatgpt.dhexx.cn/article/ekg5pNjg.shtml

相关文章

LinkedList入门教程

目录 LinkedList是什么&#xff1f;LinkedList的使用创建对象添加元素删除元素获取长度排序 常用方法 LinkedList是什么&#xff1f; LinkedList是一种数据结构&#xff0c;它由节点组成&#xff0c;每个节点包含一个值和一个指向下一个节点的指针。这种数据结构非常适合插入和…

Java--LinkedList

LinkedList的特点 LinkedList是基于双向链表实现的有序集合&#xff1b;LinkedList是非线程安全的&#xff1b;LinkedList中的元素可重复&#xff0c;可为null值&#xff1b;LinkedList可实现快速的插入和删除操作&#xff0c;与ArrayList相比&#xff0c;LinkedList的增删操作…

LinkedList 基本使用

文章目录 1. LinkedList 简介2. LinkedList 底层操作机制3. LinkedList 源码分析4. LinkedList 增删改查案例5. ArrayList和LinkedList比较 1. LinkedList 简介 LinkedList 底层实现了 双向链表和双端队列 特点可以添加任意元素(元素可以重复)&#xff0c;包括null线程不安全&…

java linkedlist poll_java之LinkedList详细介绍

1 LinkedList介绍 LinkedList简介 LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。 LinkedList 实现 List 接口&#xff0c;能对它进行队列操作。 LinkedList 实现 Deque 接口&#xff0c;即能将LinkedList当作双端队…

LinkedList简介

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。 LinkedList 实现 List 接口&#xff0c;能对它进行队列操作。 LinkedList 实现 Deque 接口&#xff0c;即能将LinkedList当作双端队列使用。 LinkedList 实现了Clo…

LinkedList特点

聊一聊LinkedList的特点吧~&#xff08;以下都是基于jdk1.8&#xff09; 继承树 LinkedList的继承树如下图&#xff1a; 特点 &#xff08;1&#xff09;允许null值 &#xff08;2&#xff09;内部以双向链表的形式来保存集合中的元素 /*** Pointer to first node.* Inva…

数据结构之链表(LinkedList详解)

文章目录 一、什么是LinkedList&#xff1f;二、LinkedList的使用三、LinkedList自实现四、链表实现逆序打印的两种方式&#xff08;递归和非递归&#xff09; 五、ArrayList和LinkedList有什么区别&#xff1f; 一、什么是LinkedList&#xff1f; LinkedList的底层是 双向链表…

LinkedList用法详解

一、LinkedList简单介绍 LinkedList是List接口的实现类&#xff0c;因此也实现了List的方法。但LinkedList是采用链表结构的方式来实现List接口的&#xff0c;因此在进 行insert 和remove动作时效率要比ArrayList高。 二、LinkedList的用法介绍 1、add和push 通过这两种方法均…

Java集合类——LinkedList(单链表及双链表)

一&#xff0c;ArrayList的缺陷 1.空间浪费 在之前的博客中&#xff0c;我利用源码详细的讲解了ArrayList这个集合类&#xff08;尤其是扩容机制&#xff09;&#xff0c;可以知道ArrayList的底层主要是一个动态的可变数组&#xff0c;容量满的时候需要进行1.5倍扩容。但是我…

java学习之LinkedList(链表)

LinkedList&#xff1a;一种线性表&#xff0c;但不按照线性顺序存储数据&#xff08;实际上为链表&#xff09;。 链表分为单向链表和双向链表&#xff0c;实际应当还有循环链表。 单向链表&#xff1a;将一个区域分成两部分&#xff0c;分别为节点区域和数据域。 如下图所…

LinkedList和ArrayList对比各有什么优势?

一、LinkedList的概述 1. LinkedList是双向链表实现的List 2. LinkedList是非线程安全的 3. LinkedList元素允许为null&#xff0c;允许重复元素 4. LinkedList是基于链表实现的&#xff0c;因此插入删除效率高&#xff0c;查找效率低(虽然有一个加速动作) 5. LinkedList是…

LinkedList详解

文章目录 介绍继承体系 LinkedLists实现底层数组结构构造函数getFirst(),getLast()removeFirest(),removeLast(),remove(e),remove(index)删除head元素删除last元素add()addAll()clear()查找操作遍历 介绍 LinkedList同时实现了List接口和Deque对口&#xff0c;也就是收它既可…

Chrome被百度网页劫持

Chrome被百度劫持的解决办法 浏览器的运行太慢了&#xff0c;就想试试谷歌的浏览器&#xff0c;但是每次打开的都是百度的界面&#xff0c;明显就是被劫持了&#xff0c; 看了网上的好多方法都没有什么明显的效果 问题 在使用Chrome浏览器打开后直接弹出一个百度的界面这看着就…

网页被劫持怎么修复?主页被劫持修复方法

电脑的浏览器被劫持了应该怎么解决&#xff1f;小编今天就来教大家解决电脑浏览器自动跳转到一个网页中的问题。 方法步骤 1.随着网络的兴起&#xff0c;更多的小伙伴享受到网络带来的便利生活&#xff0c;其中上网浏览就是非常受欢迎的一个功能&#xff0c;但是很多不法分子看…

Google Chrome主页被iduba劫持解决方法

今天用电脑的时候发现google的主页被改成了iduba的主页&#xff0c;烦的一比&#xff0c;看了好久才解决1.查看chrome://version 在命令行处会发现带有iduba的网站&#xff0c;我这里解决了&#xff0c;就没有了 2.点开google快捷方式的属性进行修改 将命令行中的代码全部复制…

浏览器被劫持怎么解决?关于浏览器被劫持主页的处理方法

背景: 上个月重做了win10系统,系统激活过程中没有出现任何问题。重装office套装,使用暴风激活下载地址: (http://win.shibojiaa.cn/baofeng/)激活office套装后,发现所有浏览器主页被劫持。打开任何一个浏览器地址栏中显示:(http://uj7.gndh555.top/)随后跳转hao123。…

Microsoft edge 主页被劫持的处理办法

最根本的办法&#xff0c;如果是任务栏固定打开后发现主页被劫持&#xff0c;应该是弄明白任务栏的链接是来自电脑的开始页面还是桌面的快捷方式。 如果是开始界面应用固定于任务栏&#xff0c;那么找到开始界面的Microsoft edge&#xff0c;右键然后找到所在文件夹。 找到开始…

浏览器主页被劫持,跳转hao123解决办法!

劫 持 指 南 前戏-疑难杂症小妙招 当打开电脑准备划水时&#xff0c;结果一打开浏览器&#xff0c;就发现它自动打开一个新的链接&#xff0c;紧接着又跳转到一个特定网页上去了&#xff0c;大家肯定心里那个气啊&#xff0c;打开百度一顿搜索&#xff0c;试了各种方法都不行…

百度主页被“/?tn=88093251_85_hao_pg“劫持的一种解决办法

前言 在闲暇之余换了个系统&#xff0c;为了方便使用了在线的小白一键装机安装的win10专业版&#xff0c;先抛开携带的各种垃圾软件不说&#xff0c;最不爽的还是主页无论如何修改都被百度劫持。 内容 尝试了网上各种解决办法&#xff0c;其中包括但不限于&#xff1a; 下…

Chrome主页被劫持怎么破

之前遇到Chrome被2345劫持了&#xff0c;导致的结果是每天初次打开Chrome都会进入2345的流氓主页&#xff0c;尝试了若干解决办法&#xff0c;最终得以解决。现简要记录一下所尝试过的方法以及解决过程&#xff0c;以下所涉及到的任何一种能够方法都有可能导致Chrome浏览器的劫…