Java LinkedList 深度解析:原理、用法与性能优化

Java LinkedList 是 List 和 Deque 接口的实现之一。它是经常使用的 List 实现类之一。它继承了 AbstractSequentialList 并实现了 List 和 Deque 接口。它是一个有序的集合,支持重复元素。它按照插入顺序存储元素。它支持添加空元素。它支持基于索引的操作。如果你想了解更多关于 List 基础知识的话,请阅读这篇文章:Java List。

摘要:目录大纲

在这篇文章中,我们将讨论以下概念。

  • Java LinkedList
  • Java LinkedList Class Diagram
  • Java LinkedList List Methods
  • Java LinkedList Deque Methods
  • Java LinkedList Basic Example
  • Java LinkedList Generics
  • Java Array to LinkedList
  • Java LinkedList to Array
  • Java LinkedList Real-time Usecases
  • Internal Representation of Java LinkedList
  • How Insertion works in Java LinkedList?
  • How Deletion works in Java LinkedList?
  • Java LinkedList Deque Operations
  • Java SE 8: Java LinkedList to Stream
  • Java SE 9 LinkedList

Java链表

在这一部分中,我们将讨论一些关于Java LinkedList的重要要点。

  • Java LinkedList class is a member of the Java Collections Framework.
  • It is an implementation of the List and Deque interfaces.
  • Internally, it is an implemented using Doubly Linked List Data Structure.
  • It supports duplicate elements.
  • It stores or maintains it’s elements in Insertion order.
  • We can add any number of null elements.
  • It is not synchronised that means it is not Thread safe.
  • We can create a synchronised LinkedList using Collections.synchronizedList() method.
  • In Java applications, we can use it as a List, stack or queue.
  • It does not implement RandomAccess interface. So we can access elements in sequential order only. It does not support accessing elements randomly.
  • When we try to access an element from a LinkedList, searching that element starts from the beginning or end of the LinkedList based on where that elements is available.
  • We can use ListIterator to iterate LinkedList elements.
  • From Java SE 8 on-wards, we can convert a LinkedList into a Stream and vice-versa.
  • Java SE 9 is going to add couple of factory methods to create an Immutable LinkedList.

Java中的LinkedList类图

Java中LinkedList的List方法

– add()方法向列表的末尾添加元素。
– addFirst()方法在列表开头添加元素。
– addLast()方法在列表末尾添加元素。
– remove()方法从列表中移除指定元素的第一个匹配项。
– removeFirst()方法从列表中移除第一个元素。
– removeLast()方法从列表中移除最后一个元素。
– get()方法返回指定位置的元素。
– getFirst()方法返回列表的第一个元素。
– getLast()方法返回列表的最后一个元素。
– size()方法返回列表中的元素数量。

在本节中,我们将讨论一些有用且经常使用的Java LinkedList方法。以下方法是从List或Collection接口继承的:

    size(): 返回列表中的元素数量。
    isEmpty(): 检查列表是否为空。
    contains(Object o): 如果列表包含指定的元素,则返回true。
    iterator(): 返回一个按适当顺序遍历列表中元素的迭代器。
    toArray(): 返回包含列表中所有元素的数组,按适当顺序排列。
    add(E e): 将指定元素追加到列表的末尾。
    remove(Object o): 从列表中移除第一个匹配到的指定元素。
    retainAll(Collection c): 仅保留列表中包含在指定集合中的元素。
    clear(): 从列表中移除所有元素。
    get(int index): 返回列表中指定位置的元素。
    set(int index, E element): 用指定元素替换列表中指定位置的元素。
    listIterator(): 返回一个列表中元素的列表迭代器。
    subList(int fromIndex, int toIndex): 返回列表中指定索引范围内的部分视图,包含fromIndex(包括)到toIndex(不包括)之间的元素。返回的列表与当前列表共享同一个底层数据结构,因此返回列表中的非结构性变更将反映在当前列表中,反之亦然。

Java LinkedList Deque 方法的中文释义

以下方法专门针对LinkedList类,这些方法是从Deque接口继承而来的。

    void addFirst(E e): 在此列表的开头插入指定元素。
    void addLast(E e): 在此列表的末尾插入指定元素。
    E getFirst(): 检索但不移除此列表的第一个元素。与peekFirst方法不同的是,如果此列表为空,它会抛出一个异常。
    E getLast(): 检索但不移除此列表的最后一个元素。与peekLast方法不同的是,如果此列表为空,它会抛出一个异常。
    E remvoeFirst(): 从此列表中移除并返回第一个元素。
    E removeLast(): 从此列表中移除并返回最后一个元素。
    boolean offerFirst(E e): 在此列表的前面插入指定元素。
    boolean offerLast(E e): 在此列表的末尾插入指定元素。
    E pollFirst(): 检索并移除此列表的第一个元素,如果此列表为空,则返回null。
    E pollLast(): 检索并移除此列表的最后一个元素,如果此列表为空,则返回null。
    E peekFirst(): 检索但不移除此列表的第一个元素,如果此列表为空,则返回null。
    E peekLast(): 检索但不移除此列表的最后一个元素,如果此列表为空,则返回null。

Java LinkedList 基本示例

在这一节中,我们将讨论Java LinkedList的基本示例。在接下来的部分中,我们将探讨一些更有用的操作。例如:

import java.util.LinkedList;
import java.util.List;

public class LinkedListDemo 
{
  public static void main(String[] args) 
  {
	List names = new LinkedList();
	names.add("Rams");
	names.add("Posa");
	names.add("Chinni");
        names.add(2011);
			
	System.out.println("LinkedList content: " + names);
	System.out.println("LinkedList size: " + names.size());
  }
}

输出:

LinkedList content: [Rams, Posa, Chinni, 2011]
LinkedList size: 4

我们在这里创建了一个LinkedList对象并添加了4个元素。正如我们讨论过的,LinkedList.size()方法用于获取列表中的元素数量。注意:-在不使用泛型的情况下,Java LinkedList支持异构元素。然而,不建议在不使用泛型的情况下使用集合。让我们在接下来的部分中通过一个简单的例子来探讨Java泛型的优势和用法。

Java链表泛型

在本节中,我们将讨论如何在Java LinkedList中使用泛型。正如我们所知,Java泛型对于编写类型安全的程序和在编译时进行更强类型检查非常有用。它们还有助于消除类型转换的开销。例如:

import java.util.LinkedList;
import java.util.List;

public class LinkedListGenericsDemo
{
  public static void main(String[] args) 
  {
	List<String> names = new LinkedList<>();
	names.add("Rams");
	names.add("Posa");
	names.add("Chinni");
        // 我们不能添加非字符串类型的数据
        // names.add(2011);
			
	System.out.println("LinkedList 内容: " + names);
	System.out.println("LinkedList 大小: " + names.size());
  }
}

输出结果:

LinkedList 内容: [Rams, Posa, Chinni]
LinkedList 大小: 3

在此示例中,我们使用泛型创建了一个LinkedList对象,并向其中添加了三个字符串元素。当我们尝试向这个泛型约束为StringLinkedList中添加一个数字类型(Number)时,编译器会抛出错误,这体现了泛型的类型安全特性。

将Java数组转换为LinkedList

本节将探讨如何将Java数组转换为LinkedList对象。虽然有多种方法可以实现,但这里我们只展示一种常见的方法。示例:


import java.util.LinkedList;
import java.util.List;

public class JavaArrayToLinkedListDemo 
{
	public static void main(String[] args) 
	{
		Integer[] numbers = {1,2,3,4,5};
		List<Integer> numbersList = new LinkedList<>();
		for(Integer s : numbers){
			numbersList.add(s);
		}
		System.out.println(numbersList);
	}
}

输出结果:

[1, 2, 3, 4, 5]

将Java LinkedList转换为数组

在这一节中,我们将探讨如何将Java的LinkedList转换为数组。同样,虽然有多种实现方式,但我们在此仅提供一种常用方法。示例:

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class LinkedListToJavaArrayDemo 
{
	public static void main(String[] args) 
	{		
		List<Integer> numbersList = new LinkedList<>();
		numbersList.add(1);
		numbersList.add(2);
		numbersList.add(3);
		numbersList.add(4);
		numbersList.add(5);
		Integer[] numbers = new Integer[numbersList.size()];
		
		numbers = numbersList.toArray(numbers);
		System.out.println(Arrays.toString(numbers));

	}
}

输出结果:

[1, 2, 3, 4, 5]

Java LinkedList 的实际应用场景

在这一部分,我们将讨论在Java应用程序中使用LinkedList的最佳和最差情况。

最佳使用情况:

  • 当我们的主要操作是频繁地在列表中间添加或删除元素时,LinkedList是最佳选择。

为什么? 因为在链表中间添加或删除元素时,不需要像数组那样进行大量元素的移动。有关详细信息,请参考“Java LinkedList中插入操作的工作原理”部分。

最差使用情况:

  • 当我们的主要操作是频繁地从列表中检索元素时,LinkedList是最差的选择。

为什么? 因为LinkedList只支持顺序访问,不支持随机访问(即无法通过索引直接快速访问任意元素)。有关详细信息,请参考“在Java LinkedList中如何删除?”部分。

注意: LinkedList实现了ListDequeCloneableSerializable接口,但它实现RandomAccess接口。

Java 链表的内部表示

Java LinkedList 内部结构示意图
  1. 左侧的节点部分用于指向链表中的前一个节点(或元素)。
  2. 右侧的节点部分用于指向链表中的下一个节点(或元素)。
  3. 中间的节点部分用于存储实际数据。
Java LinkedList 节点连接示意图

在Java LinkedList 中,插入操作是如何工作的?

在前面的部分中,我们已经了解了LinkedList如何将其元素存储为节点。在本节中,我们将深入探讨Java LinkedList的插入操作在内部是如何工作的。

  1. 假设我们有一个初始的LinkedList,包含以下数据。
  2. 现在,对这个LinkedList执行以下插入操作:
linkedList.add(2,54);
Java LinkedList 插入操作示意图

在Java LinkedList 中,删除操作是如何工作的?

在前面的部分中,我们已经看到了LinkedList如何执行插入操作。在本部分中,我们将讨论Java LinkedList的删除操作是如何在内部工作的。

  1. 让我们假设初始的链表具有以下数据。
  2. 对于该链表,执行以下删除操作:
linkedList.remove(3);
Java LinkedList 删除操作示意图

Java LinkedList 的 Deque 操作

在这里,我们将探讨一个LinkedList对象作为双端队列(Deque)的工作原理。我们可以使用这些操作来实现队列或栈的数据结构。我将在后续的文章中详细讨论栈或队列的工作原理。示例:

import java.util.LinkedList;
import java.util.Deque;

public class LinkedListDequeOperationsDemo 
{
  public static void main(String[] args) 
  {
	Deque names = new LinkedList();
	names.add(2);
	names.addFirst(1);
	names.addLast(3);
	names.addFirst(0);
	names.addLast(4);
			
	System.out.println("LinkedList 内容: " + names);
	System.out.println("LinkedList 大小: " + names.size());
	names.removeFirst();
	names.removeLast();
	
	System.out.println("LinkedList 内容: " + names);
	System.out.println("LinkedList 大小: " + names.size());	
  }
}

输出结果:

LinkedList 内容: [0, 1, 2, 3, 4]
LinkedList 大小: 5
LinkedList 内容: [1, 2, 3]
LinkedList 大小: 3

Java SE 8: 将Java LinkedList 转换为 Stream

在这里,我们将探讨如何将一个LinkedList对象转换为Java SE 8中的Stream概念。示例:

这是文章《Java的LinkedList – Java中的LinkedList》的第3部分(共3部分)。

import java.util.LinkedList;
import java.util.List;

public class LinkedListToStreamDemo 
{
  public static void main(String[] args) 
  {      
    List<Integer> numbersList = new LinkedList<>();
    numbersList.add(1);
    numbersList.add(2);
    numbersList.add(3);
    numbersList.add(4);
    numbersList.add(5);
        
    // 将列表转换为流
    numbersList.stream().forEach(System.out::println);
  }
}

输出:

1
2
3
4
5

Java SE 9 中的 LinkedList

在 Java SE 9 中,Oracle 公司添加了一些有用的实用方法来创建不可变列表。如果您想通过一些实用示例深入了解它们,请阅读我的文章:Java SE 9:不可变列表的工厂方法。以上就是关于 Java 中 LinkedList 的一个快速总结。我希望这些 Java LinkedList 的示例能帮助您开始使用 LinkedList 进行编程。感谢您阅读我的教程。如果您喜欢我的教程,或者有任何问题、建议或发现任何错误,请给我留言。

bannerAds