首页 > 编程语言 >Java LinkedList与ArrayList源码解析:根本区别和表面区别的详解

Java LinkedList与ArrayList源码解析:根本区别和表面区别的详解

时间:2023-09-24 23:02:42浏览次数:34  
标签:index Java LinkedList 区别 ArrayList 元素 源码 数组 节点

在Java中,LinkedList和ArrayList是两个常见的集合类。它们都实现了List接口,但它们在实现方式上有很大的区别。本篇博客将详细解析LinkedList和ArrayList的源码,解释它们的根本区别和表面区别,并提供详细的代码解释。

  1. LinkedList与ArrayList的根本区别:
  • 数据结构:LinkedList是基于链表实现的,而ArrayList是基于数组实现的。
  • 数据访问:LinkedList通过节点之间的链接进行数据访问,而ArrayList直接通过索引访问数组中的元素。
  1. LinkedList与ArrayList的表面区别: 2.1 内存占用:
  • LinkedList:由于需要存储节点本身和节点之间的链接,LinkedList的内存消耗比较大。
  • ArrayList:只需存储数组和元素本身,所以ArrayList相对较省内存。

2.2 插入和删除操作:

  • LinkedList:由于是基于链表的数据结构,插入或删除元素时只需要调整节点之间的链接,因此插入和删除操作的时间复杂度为O(1)。
  • ArrayList:由于是基于数组的数据结构,插入或删除元素时需要移动数组中的元素,时间复杂度为O(n)。

2.3 随机访问操作:

  • LinkedList:由于需要从头节点开始遍历链表直到达到目标节点,所以随机访问元素的时间复杂度为O(n)。
  • ArrayList:由于使用数组实现,可以通过索引直接访问数组中的元素,所以随机访问元素的时间复杂度为O(1)。
  1. LinkedList源码解析: LinkedList的底层实现是一个双向链表,其中的每个节点(Node)都包含了元素值、前驱节点和后继节点。它通过节点之间的链接来实现数据的添加、删除和访问操作。下面是LinkedList源码的详细解释及关键方法解析:
public class LinkedList<E> extends AbstractSequentialList<E>
        implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
    private Node<E> first; // 链表的第一个节点
    private Node<E> last; // 链表的最后一个节点
    private int size; // 链表的大小

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

    // 在链表指定位置插入元素
    public void add(int index, E element) {
        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

    // 删除链表指定位置的元素
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

    // 获取链表指定位置的元素
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    
    // 省略其他方法...
}

解释:上述代码展示了LinkedList类的部分源码。LinkedList的底层是一个双向链表,其中每个节点(Node)都包含了元素值、前驱节点和后继节点。通过addremoveget等方法,可以实现对链表的增删改查操作。

  1. ArrayList源码解析: ArrayList的底层实现是一个动态数组,使用数组来保存元素。在添加元素时,如果数组容量不足,ArrayList会进行扩容操作。下面是ArrayList源码的详细解释及关键方法解析:
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    private static final int DEFAULT_CAPACITY = 10; // 默认初始容量
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private transient Object[] elementData; // 真实存储元素的数组
    private int size; // 数组的大小

    // 构造方法
    public ArrayList() {
        this.elementData = EMPTY_ELEMENTDATA;
    }
    
    // 添加元素到数组末尾
    public boolean add(E e) {
        ensureCapacityInternal(size + 1); // 确保数组容量足够
        elementData[size++] = e; // 将元素添加到数组末尾
        return true;
    }

    // 在数组指定位置插入元素
    public void add(int index, E element) {
        rangeCheckForAdd(index); // 检查插入位置是否合法
        ensureCapacityInternal(size + 1); // 确保数组容量足够
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index); // 移动元素,腾出插入位置
        elementData[index] = element; // 在指定位置插入元素
        size++; // 数组大小加1
    }

    // 删除数组指定位置的元素
    public E remove(int index) {
        rangeCheck(index); // 检查删除位置是否合法
        modCount++;
        E oldValue = elementData(index);
        int numMoved = size - index - 1; // 需要移动的元素个数
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                     numMoved); // 移动元素,覆盖删除位置
        elementData[--size] = null; // 释放最后一个元素
        return oldValue;
    }

    // 获取数组指定位置的元素
    public E get(int index) {
        rangeCheck(index); // 检查索引是否合法
        return elementData(index);
    }
    
    // 省略其他方法...
}

解释:上述代码展示了ArrayList类的部分源码。ArrayList的底层是一个动态数组,通过addremoveget等方法,可以实现对数组的增删改查操作。当数组容量不足时,ArrayList会进行扩容以确保数组大小的合适。

  1. 性能比较和适用场景:
  • LinkedList适用于频繁的插入和删除操作,尤其是在列表的中间位置。它的插入和删除操作效率高。
  • ArrayList适用于频繁的随机访问操作,尤其是在列表的末尾位置。它的随机访问效率高。

总结: 通过以上内容,您了解了LinkedList和ArrayList的根本区别和表面区别,并提供了详细的代码解释。LinkedList适用于频繁的插入和删除操作,而ArrayList适用于频繁的随机访问操作。根据实际需求,选择合适的集合类可以提高代码的效率和性能。

希望本篇博客对您理解和应用LinkedList和ArrayList有所帮助。如有更多问题,请参考Java官方文档和其他相关资源,以加深您的学习。祝您在应用LinkedList和ArrayList时取得成功!

标签:index,Java,LinkedList,区别,ArrayList,元素,源码,数组,节点
From: https://blog.51cto.com/u_15941034/7589358

相关文章

  • JAVA语法&包和访问控制
    目录前言一、Java包概述1.包的简介2.包的语法3.包的命名规则4.JDK类库里的包 5.怎么导包二、访问控制1.访问权限修饰符2.Static关键字作用前言在编写 Java一、Java包概述1.包的简介计算机中存放了若干类型的文档,为了管理方便,操作系统采用了树形结构的文件夹形式存放这些文档,并对......
  • 简单而经典:Java中的冒泡排序算法详解
    当谈到简单的排序算法时,冒泡排序(BubbleSort)通常是其中之一。虽然它不是最高效的排序算法之一,但它的简单性和易于理解使它成为学习排序算法的良好起点。在本文中,我们将详细介绍Java中的冒泡排序。冒泡排序的基本原理冒泡排序(BubbleSort)是一种简单的排序算法,它通过多次遍历待排序的......
  • threejs源码
    剖分管道形状面地表文字水体相交光线三维实体材质运动svg动画输出......
  • Java连接MSSQL2012数据报TLS10 is not accepted by client preferences [TLS13, TLS12
    这一问题好像是因为Java新版本禁用了些老的加密算法引起的,解决方法为修改java.security文件里的配置信息即可。我用的是Java21,在安装目录 Java\jdk-21\conf\security下找到java.security文件,用记事本打开,搜索TLSv1,大概在752行的位置有如下配置信息:jdk.tls.disabledAlgorithm......
  • Java 21 正式发布!新特性专栏继续更起来了~
    就在昨天晚间,Oracle公司宣布Java21正式发布。该版本是继JDK17之后最新的长期支持版本(LTS),将获得至少8年的支持!Java21号称具有数千项性能、稳定性和安全性改进。新的JDK21包括对15项改进的抢先体验,这些增强功能是在OracleCloudWorld2023会议上宣布的,包括支持虚拟线程以......
  • linux教程:cd $_与cd -有什么区别
    cd$_和cd-都是用于在命令行中切换工作目录的命令,但它们之间有一些区别。cd$_:$_是一个特殊变量,表示上一个执行命令的参数。在这种情况下,$_表示上一个命令的参数,即上一个cd命令所切换到的目录。因此,cd$_将切换到上一个命令所切换的目录。cd-:-(短横线)是一个特殊的目录名,表示前一个......
  • Java语法学习——运算符
    一、基本的算术运算符、+符号做连接符1.基本的算术运算符   为了掌握基本的算术运算符的使用,我们在IDEA里新建一个package(it.com.operator),然后在这下面新建一个Javaclass(OperatorDemo1):packageit.com.operator;publicclassOperatorDemo1{publicstaticvoid......
  • Java课堂
    importjava.awt.*;importjava.awt.event.*;importjava.util.*;publicclassMain{publicstaticdoublemax(double...values){doublelargest=Double.MIN_VALUE;for(doublev:values)if(v>largest)largest=v;......
  • 字符设备和块设备的区别
    字符设备字符以每个字符为单位进行读写操作设备。它们是一种逐字符流式设备,字符都是独立的。例如,键盘、USB、串口设备等通常被视为字符设备,因为它们接受和发送单个字符或字节的数据。字符通常不支持随机访问,设备只能按顺序访问数据。因此,无法像文件系统那样以块为单......
  • 无涯教程-JavaScript - RANK.AVG函数
    描述RANK.AVG函数在提供的值数组中返回给定值的统计等级。如果列表中有重复值,则返回平均排名。语法RANK.AVG(number,ref,[order])争论Argument描述Required/OptionalNumberThenumberwhoserankyouwanttofind.RequiredRefAnarrayof,orareferenceto,a......