目录

ArrayList 和 LinkedList 的深度对比:原理、性能与应用场景

一、区别维度

1. 底层数据结构

2. 操作数据的效率

3. 内存占用

4. 线程安全问题

二、代码示例

1. Java 代码

2. 前端 Vue3 + TS 代码(模拟展示 ArrayList 和 LinkedList 数据,这里假设通过 API 获取数据)

3. Python 代码(Python 中没有和 Java 完全一样的 ArrayList 和 LinkedList,但可以用列表和自定义链表类来模拟部分功能)


在这篇博客中,我们将深入探讨 Java 中 ArrayList 和 LinkedList 的区别,这是一个在面试中高频出现且非常重要的知识点。理解它们之间的差异对于在不同应用场景下选择合适的集合类型、优化程序性能以及应对面试问题都有着关键作用。

一、区别维度

1. 底层数据结构

ArrayList 的底层是动态数组。这意味着它在内存中是连续存储元素的,就像一排紧密排列的盒子,每个盒子存放一个元素。不过,由于它是动态的,当元素数量超过数组当前容量时,需要进行扩容操作,这个过程涉及到数组的拷贝。而 LinkedList 是双向链表结构,每个节点不仅包含数据,还包含指向前一个节点和后一个节点的指针,就像一条由多个带有连接的链环组成的链子。

2. 操作数据的效率

  • 查询效率:ArrayList 支持按照索引查询,时间复杂度为 O (1)。这是因为其内存连续,通过简单的计算就能直接定位到要查询的元素,就像根据门牌号快速找到对应的房子一样。而 LinkedList 不支持下标查询,因为要找到某个节点,需要从链表头或链表尾开始逐个遍历,没有像 ArrayList 那样直接的索引定位方式。
  • 无索引查询、新增和删除效率:当不知道索引时,无论是 ArrayList 还是 LinkedList,查询元素都需要遍历,时间复杂度都是 O (n)。对于新增和删除操作,ArrayList 在尾部插入和删除元素的时间复杂度为 O (1),但如果是在其他部分插入或删除元素,由于需要挪动数组中的元素来保持连续性,时间复杂度变为 O (n)。LinkedList 在头尾节点进行新增和删除操作的效率很高,时间复杂度为 O (1),因为只需要调整相关节点的指针即可。但对于其他节点的增删操作,同样需要遍历链表,时间复杂度为 O (n)。

3. 内存占用

ArrayList 基于连续内存的数组,相对比较节省内存空间。而 LinkedList 除了存储数据本身,每个节点还需要额外存储两个指针(指向前一个和后一个节点),这使得它在内存占用上相对较多。

4. 线程安全问题

ArrayList 和 LinkedList 本身都不是线程安全的。在实际项目中,如果要保证它们的线程安全,通常有以下两种方式。一种是尽可能在方法内部使用它们,因为方法内定义的变量是局部变量,每个线程都有自己的一份副本,不存在线程间共享数据的问题,从而避免了线程安全隐患。另一种方式是使用 Java 中的 Collections 工具类,例如调用 Collections.synchronizedList() 方法来包装 ArrayList 或 LinkedList。当使用包装后的集合操作数据时,它就变成了线程安全的,不过需要注意的是,这种方式会因为加锁机制而在一定程度上降低性能。

二、代码示例

1. Java 代码

  • ArrayList 示例
import java.util.ArrayList;

public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        // 添加元素
        arrayList.add("Element 1");
        arrayList.add("Element 2");
        // 按索引查询元素
        System.out.println(arrayList.get(0)); 
        // 输出: Element 1
    }
}

  • LinkedList 示例
import java.util.LinkedList;

public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        // 在头部添加元素
        linkedList.addFirst("Node 1");
        // 在尾部添加元素
        linkedList.addLast("Node 2");
        // 获取头部元素
        System.out.println(linkedList.getFirst()); 
        // 输出: Node 1
    }
}

  • 使用 Collections 工具类实现线程安全示例(以 ArrayList 为例)
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ThreadSafeArrayListExample {
    public static void main(String[] args) {
        List<String> synchronizedArrayList = Collections.synchronizedList(new ArrayList<>());
        // 可以在多线程环境下安全地操作 synchronizedArrayList
    }
}

2. 前端 Vue3 + TS 代码(模拟展示 ArrayList 和 LinkedList 数据,这里假设通过 API 获取数据)

  • 展示 ArrayList 数据
<template>
  <div>
    <h2>ArrayList Data</h2>
    <ul>
      <li v-for="(item, index) in arrayListData" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

const arrayListData = ref<string[]>([]);

onMounted(async () => {
  const response = await fetch('your_api_url_for_arraylist_data');
  const data: string[] = await response.json();
  arrayListData.value = data;
});
</script>

  • 展示 LinkedList 数据
<template>
  <div>
    <h2>LinkedList Data</h2>
    <ul>
      <li v-for="(item, index) in linkedListData" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

const linkedListData = ref<string[]>([]);

onMounted(async () => {
  const response = await fetch('your_api_url_for_linkedlist_data');
  const data: string[] = await response.json();
  linkedListData.value = data;
});
</script>

3. Python 代码(Python 中没有和 Java 完全一样的 ArrayList 和 LinkedList,但可以用列表和自定义链表类来模拟部分功能)

  • Python 列表(类似 ArrayList 的部分功能)示例
my_list = []
my_list.append("Element 1")
my_list.append("Element 2")
print(my_list[0])  
# 输出: Element 1

  • 简单的 Python 链表类示例(模拟 LinkedList 的部分功能)
# 链表节点类
class ListNode:
    def __init__(self, data=None):
        self.data = data
        self.next = None

# 链表类
class LinkedList:
    def __init__(self):
        self.head = None

    def add_at_head(self, data):
        new_node = ListNode(data)
        new_node.next = self.head
        self.head = new_node

    def print_list(self):
        current = self.head
        while current:
            print(current.data)
            current = current.next

可以使用以下方式测试这个 Python 链表类:

my_linked_list = LinkedList()
my_linked_list.add_at_head("Node 1")
my_linked_list.add_at_head("Node 2")
my_linked_list.print_list() 

通过对 ArrayList 和 LinkedList 在底层数据结构、操作效率、内存占用和线程安全等方面的详细对比,我们能更清晰地了解它们各自的特点,从而在开发中根据具体需求合理选择使用,也能更好地应对相关的面试问题。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐