Java ArrayList和LinkedList

ArrayList

ArrayList是Java中最常用的数据结构之一,它是一个动态数组的实现,允许你在程序中存储和管理一个可变大小的对象列表,我们可以添加或删除元素。

ArrayList 继承了 AbstractList ,并实现了 List 接口。

基本概念

ArrayList是List接口的一个实现类,它允许存储任意类型的对象,并且可以动态调整其大小。

List接口表示一个有序的集合,其中的元素可以重复,每个元素都有一个整数索引表示其位置。

动态数组:ArrayList使用一个数组作为其底层数据结构,当数组的空间不足时,ArrayList会自动扩展数组的大小。

内部结构

数组:ArrayList内部维护了一个对象数组,用于存储元素。

容量:ArrayList有一个内部的容量,即数组的大小。当添加的元素超过了当前容量时,ArrayList会创建一个新的更大的数组,并将旧数组中的所有元素复制到新数组中。

扩展策略:默认情况下,ArrayList在需要更多空间时会将数组的大小增加50%,但你可以通过构造函数指定初始容量或增量策略。

特点

可变性:ArrayList的大小是可变的,你可以随时添加或删除元素。

索引访问:ArrayList支持通过索引访问元素,这使得随机访问非常快。

线程不安全:ArrayList不是线程安全的,如果你需要在多线程环境中使用它,你需要自己进行同步控制。

允许null值:ArrayList允许存储null值。

常用方法

添加元素:add(E e) - 向列表的末尾添加一个元素。

获取元素:get(int index) - 返回指定索引处的元素。

设置元素:set(int index, E element) - 替换指定索引处的元素。

删除元素:remove(int index) - 删除指定索引处的元素。

迭代器:iterator() - 返回一个迭代器,用于遍历列表中的元素。

示例代码

下面是一个简单的示例,展示了如何使用ArrayList:

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        // 创建一个 ArrayList
        List<String> programmingLanguages = new ArrayList<>();

        // 添加元素
        programmingLanguages.add("Java");
        programmingLanguages.add("C");
        programmingLanguages.add("Python");
        programmingLanguages.add("C++");
        programmingLanguages.add("Visual Basic .NET");
        programmingLanguages.add("JavaScript");

        // 获取元素
        String firstLanguage = programmingLanguages.get(0);
        System.out.println("First language: " + firstLanguage);

        // 设置元素
        programmingLanguages.set(0, "Kotlin");
        System.out.println("Updated first language: " + programmingLanguages.get(0));

        // 删除元素
        programmingLanguages.remove(1); // 删除索引为1的元素
        System.out.println("After removing an element: " + programmingLanguages);

        // 遍历元素
        for (String language : programmingLanguages) {
            System.out.println(language);
        }
    }
}

当你运行这段代码时,它将输出更新后的列表和每个编程语言的名称。

深入理解

容量和扩展:ArrayList的默认初始容量为10。当添加元素导致当前数组容量不足时,ArrayList会创建一个新的数组,其大小通常是原数组大小的1.5倍,并将所有元素复制到新的数组中。

性能:由于ArrayList使用数组作为底层数据结构,因此随机访问非常快(O(1))。但是,插入或删除元素(尤其是在列表的中间位置)可能导致大量的元素移动,这可能会很慢(O(n))。

内存消耗:由于ArrayList可能需要预留额外的空间来容纳更多的元素,因此它可能会占用比实际需要更多的内存。

使用场景

当你需要一个可以动态扩展的有序列表时,ArrayList是一个很好的选择。

如果你需要频繁地进行随机访问,但插入和删除操作相对较少,那么ArrayList非常适合。

在需要快速随机访问的场景中,如索引数据库记录、缓存、配置文件等。

LinkedList

LinkedList是Java集合框架中的一个重要组成部分,它是一种基于双向链表实现的List接口。

基本概念

LinkedList是List接口的一个实现类,它使用双向链表来存储元素。

List接口定义了一个有序集合,允许重复元素,并且可以通过索引访问元素。

双向链表是一种数据结构,其中每个元素(节点)包含一个指向其前一个节点的引用和一个指向其后一个节点的引用。

内部结构

节点:LinkedList中的每个元素都是一个节点,每个节点包含两个部分:数据和两个引用(一个指向前一个节点,另一个指向后一个节点)。

头节点和尾节点:LinkedList维护了对头节点和尾节点的引用,这使得在链表两端添加和删除元素变得非常高效。

特点

插入和删除操作高效:由于LinkedList使用双向链表实现,因此在链表的任意位置插入或删除元素都非常高效,只需要更新相邻节点的引用即可。

随机访问较慢:与基于数组的ArrayList相比,LinkedList的随机访问(通过索引访问元素)较慢,因为需要从头节点开始遍历链表直到找到目标节点。

允许重复元素:LinkedList允许存储重复元素。

线程不安全:LinkedList不是线程安全的。如果多个线程同时访问或修改链表,则需要外部同步机制。

示例代码

下面是一个简单的示例,展示了如何使用LinkedList:

java 复制代码
import java.util.LinkedList;
import java.util.List;

public class LinkedListExample {
    public static void main(String[] args) {
        // 创建一个 LinkedList
        List<String> languages = new LinkedList<>();

        // 添加元素
        languages.add("Java");
        languages.add("C");
        languages.add("Python");

        // 在指定位置插入元素
        languages.add(1, "C++");

        // 删除元素
        languages.remove("C");

        // 获取元素
        String firstLanguage = languages.getFirst(); // 或者 languages.get(0)
        String lastLanguage = languages.getLast();

        // 遍历并打印元素
        for (String language : languages) {
            System.out.println(language);
        }
    }
}

当你运行这段代码时,它将输出:

java 复制代码
Java
C++
Python

深入理解

内部实现:LinkedList的每个节点包含一个next引用指向下一个节点,一个prev引用指向前一个节点,以及一个item来存储实际的数据。

迭代器:LinkedList提供了高效的迭代器实现,可以用来遍历链表中的元素。

性能:LinkedList在插入和删除操作上的性能优于ArrayList,尤其是在链表的中间位置,但随机访问操作不如ArrayList高效。

使用场景

频繁的插入和删除操作:如果你需要在列表中频繁插入和删除元素,那么LinkedList是一个很好的选择。

不确定大小的列表:如果你不确定列表最终会有多大,或者列表的大小会动态变化,LinkedList是一个好的选择,因为它不需要像ArrayList那样预留额外的空间。

不需要频繁随机访问:如果大部分操作是插入和删除,并且不需要频繁地根据索引访问元素,那么LinkedList非常适合。

ArrayList、LinkedList和Vector的相同点和不同点

ArrayList, LinkedList, 和 Vector 都是 Java 中 List 接口的具体实现类,它们都提供了存储和操作有序集合的功能。下面是它们之间的一些相同点和不同点:

相同点

  1. 实现了 List 接口:

    • 它们都实现了 List 接口,因此支持 List 接口中定义的所有方法,比如 add(), remove(), get(), set() 等。
  2. 允许 null 元素:

    • 这三个类都允许在列表中存储 null 元素
  3. 索引访问:

    • 它们都可以通过索引来访问元素。
  4. 有序性:

    • 这些类都是有序的,即元素按照添加顺序保存。
  5. 可变性:

    • 它们都是可变的,意味着可以在列表中添加、删除或修改元素。

不同点

  1. 数据结构:

    • ArrayList: 基于动态数组实现。当空间不足时,会自动扩展数组的容量。

    • LinkedList: 基于双向链表实现。每个元素都有一个指向前一个元素和后一个元素的引用。

    • Vector: 与 ArrayList 类似,也是基于动态数组实现,但它是线程同步的。

  2. 性能特点:

    • ArrayList: 对于随机访问(如 get(int index) 和 set(int index, E element))非常高效,因为可以通过索引直接访问。但是插入和删除操作(尤其是中间位置的操作)效率较低,因为需要移动大量的元素。

    • LinkedList: 插入和删除操作非常快,因为它只需要改变前后节点的引用即可。然而,随机访问效率较低,因为需要从头开始遍历链表直到找到目标节点。

    • Vector: 性能特征类似于 ArrayList,但由于同步机制的存在,多线程环境下的性能较低。

  3. 线程安全性:

    • ArrayList 和 LinkedList: 都不是线程安全的。如果多个线程同时访问或修改这些列表,则需要外部同步机制。

    • Vector: 是线程安全的,它的许多方法都是同步的,可以直接在多线程环境中使用而不需要额外的同步。

  4. 初始化容量和增长策略:

    • ArrayList: 默认初始容量为10,每次扩容通常增加50%。

    • LinkedList: 没有固定的容量限制,因为它是基于链表实现的。

    • Vector: 默认初始容量为10,每次扩容通常增加100%。可以通过构造函数指定初始容量和增量。

  5. 其他特性:

    • Vector 还包含了一些额外的方法,例如 addElement(), insertElementAt(), removeElement(), removeElementAt(), 这些方法是为了向后兼容早期的 Vector API 设计。

选择哪个类取决于具体的应用场景。如果需要频繁地进行插入和删除操作,或者经常需要处理大量数据,LinkedList 可能更适合。如果需要快速随机访问,并且插入删除操作较少,那么 ArrayList 更合适。而 Vector 则适用于需要线程安全的场景。

相关推荐
Scott9999HH5 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔5 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社6 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海6 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖7 小时前
JDK 26 新特性详解
java·开发语言
马优晨8 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区9 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大10 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai10 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说10 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json