ArrayList和LinkedList的区别与联系

本文通过实验对比了ArrayList和LinkedList在不同场景下的性能表现,包括在列表结尾添加元素、在任意位置插入元素、删除任意位置元素及遍历操作等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArrayList和Vector使用了数组去实现。
LinkedList使用了链表数据结构
这是两种不同的技术,所以使用它们的时候是有区别的。

1)首先我们来看看增加到List结尾的场景。如果ArrayList的容量在初始化的时候,设置的足够大。那么此时ArrayList的性能是非常好的。但是如果ArrayList的容量是10的话,那么超出了现有的数组的长度是要进行自动扩容的。扩容的公式是 (oldLength * 3 ) / 2 + 1
这就要涉及到大量的数组的复制操作
我们在来看一看LinkedList由于它是链表结构的,所以不需要维护容量的大小,从这点说,他比ArrayList有一定的优势。然而,每次的元素增加都需要新建一个Entry对象,并进行更多的赋值操作。在频繁的系统调用中,对性能会产生一定的影响
下面我们来写个程序测试一下。

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

public class ListTest {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        long arrayListStartTime = System.currentTimeMillis();
        for(int i = 0 ; i < 10000 ; i++) {
            arrayList.add("a" + i);
        }

        System.out.println("ArrayList在尾部增加元素消耗了" + (System.currentTimeMillis() - arrayListStartTime));

        LinkedList<String> linkedList = new LinkedList<>();
        long linkedListStartTime = System.currentTimeMillis();

        for(int i = 0 ; i < 10000 ; i++) {
            linkedList.add("a" + i);
        }
        System.out.println("LinkedList在尾部增加元素消耗了" + (System.currentTimeMillis() - linkedListStartTime));

    }
}

这里写图片描述

2)增加元素到列表任意位置
当增加元素到链表任意位置的时候,LinkedList的优势就体现出来了。因为ArrayList是数组实现的。所以肯定要移动数组元素,而且插入的位置越靠前,性能影响越大。由于LinkedList是链表实现的。所以只需要改变指针指向就可以了。

我们来写个程序来测试下

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

public class ListTest {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        long arrayListStartTime = System.currentTimeMillis();
        for(int i = 0 ; i < 1000000 ; i++) {
            arrayList.add("a" + i);
        }

        System.out.println("ArrayList在尾部增加元素消耗了" + (System.currentTimeMillis() - arrayListStartTime));

        LinkedList<String> linkedList = new LinkedList<>();
        long linkedListStartTime = System.currentTimeMillis();

        for(int i = 0 ; i < 1000000 ; i++) {
            linkedList.add("a" + i);
        }
        System.out.println("LinkedList在尾部增加元素消耗了" + (System.currentTimeMillis() - linkedListStartTime));


        System.out.println("=====================================");

        long addElementInArrayListAnyWhereBegin = System.currentTimeMillis();
        for(int i = 0 ; i < 10000 ; i++) {
            arrayList.add(i, "aaa");
        }

        System.out.println("ArrayList在任意位置插入元素消耗了" + (System.currentTimeMillis() - addElementInArrayListAnyWhereBegin));


        long addElementInLinkedListAnyWhereBegin = System.currentTimeMillis();
        for(int i = 0 ; i < 10000 ; i++) {
            linkedList.add(i, "aaa");
        }

        System.out.println("LinkedList在任意位置插入元素消耗了" + (System.currentTimeMillis() - addElementInLinkedListAnyWhereBegin));

    }
}

这里写图片描述

3)删除任意位置元素
这个跟任意位置插入有点像。
在删除掉后ArrayList是要进行移动的。
并且删除的位置越靠前,开销越大。
4)容量参数
ArrayList是要维护一个容量大小的。如果我们知道我们大概要存放多少的元素。我们应该在ArrayList的构造方法中声明出来。从而减少数组的扩容次数。性能自然就上来了。
5)遍历操作
当我们在遍历的时候,
先上一张图吧
这里写图片描述

我们也来写个程序测一下

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

public class ListTest {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        long arrayListStartTime = System.currentTimeMillis();
        for(int i = 0 ; i < 1000000 ; i++) {
            arrayList.add("a" + i);
        }

        System.out.println("ArrayList在尾部增加元素消耗了" + (System.currentTimeMillis() - arrayListStartTime));

        LinkedList<String> linkedList = new LinkedList<>();
        long linkedListStartTime = System.currentTimeMillis();

        for(int i = 0 ; i < 1000000 ; i++) {
            linkedList.add("a" + i);
        }
        System.out.println("LinkedList在尾部增加元素消耗了" + (System.currentTimeMillis() - linkedListStartTime));


        System.out.println("=====================================");

        long addElementInArrayListAnyWhereBegin = System.currentTimeMillis();
        for(int i = 0 ; i < 10000 ; i++) {
            arrayList.add(i, "aaa");
        }

        System.out.println("ArrayList在任意位置插入元素消耗了" + (System.currentTimeMillis() - addElementInArrayListAnyWhereBegin));


        long addElementInLinkedListAnyWhereBegin = System.currentTimeMillis();
        for(int i = 0 ; i < 10000 ; i++) {
            linkedList.add(i, "aaa");
        }

        System.out.println("LinkedList在任意位置插入元素消耗了" + (System.currentTimeMillis() - addElementInLinkedListAnyWhereBegin));


        System.out.println("=================================");

        StringBuffer stringBuffer = new StringBuffer();
        long getAllArrayListBegin = System.currentTimeMillis();
        for(int i = 0 ; i < arrayList.size(); i++) {
            stringBuffer.append(arrayList.get(i));
        }

        System.out.println("遍历ArrayList消耗了" + (System.currentTimeMillis() - getAllArrayListBegin));


        long getAllLinkedListBegin = System.currentTimeMillis();
        for(int i = 0 ; i < linkedList.size(); i++) {
            stringBuffer.append(linkedList.get(i));
        }

        System.out.println("遍历LinkedList消耗了" + (System.currentTimeMillis() - getAllLinkedListBegin));
    }
}

就不上运行截图了,因为等了很久也没有出结果。读者可以复制代码运行下看看

### Java中ArrayListLinkedList区别 #### 1. **底层数据结构** - `ArrayList` 是基于动态数组实现的,其内部维护了一个对象数组。当容量不足时,会自动扩容以容纳更多元素[^1]。 - `LinkedList` 则是一个双向链表结构,每个节点包含前驱指针、后继指针以及当前存储的数据项。这种设计使得它更适合频繁插入删除的操作[^2]。 #### 2. **性能对比** ##### 2.1 随机访问 - 对于随机访问(通过索引获取元素),`ArrayList` 提供 O(1) 时间复杂度的支持,因为它可以直接计算目标位置并返回相应值[^3]。 - 而 `LinkedList` 的随机访问效率较低,达到某个指定索引处的时间复杂度为 O(n),因为需要从头或者尾遍历至该位置[^4]。 ##### 2.2 插入删除 - 当涉及到中间位置上的插入或移除操作时,`ArrayList` 可能较慢,原因是这些动作可能引发大量后续元素向左或右整体平移的过程,平均时间复杂度接近 O(n)[^5]。 - 相反,在相同情况下,由于 `LinkedList` 不必调整其他部分仅需改变几个链接关系即可完成任务,因此它的此类操作通常更快一些,具有常数级即 O(1) 的理想情况下的表现[^6]。 ##### 2.3 内存占用 - 尽管如此,值得注意的是尽管单次增删更高效但每增加一个新项目到 `LinkedList` 中都需要额外分配两个引用空间用于保存前后连接信息,这导致总体内存消耗大于同等长度下简单连续排列形式呈现出来的 `ArrayList` 结构[^7]。 #### 3. **使用场景** ##### 适合使用 ArrayList 的场景: - 如果应用程序主要涉及大量的读取操作而非写入/修改,则应优先考虑采用 `ArrayList` ,因其提供了快速定位任意元素的能力[^8]。 ##### 适合使用 LinkedList 的场景: - 若业务逻辑里存在许多顺序无关紧要却经常发生的变化比如队列模拟等问题解决方案构建过程中的临时缓冲区管理等方面可以选用 `LinkedList` 来优化运行速度减少不必要的位移开销从而提升整个系统的响应速率[^9]。 ```java // ArrayList 示例代码 import java.util.ArrayList; public class Main { public static void main(String[] args){ ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("Element"); String element = arrayList.get(0); // 快速访问第一个元素 } } // LinkedList 示例代码 import java.util.LinkedList; public class Main { public static void main(String[] args){ LinkedList<Integer> linkedList = new LinkedList<>(); linkedList.addFirst(1); linkedList.removeLast(); // 效率高的首尾操作 Integer firstElement = linkedList.getFirst(); } } ``` #### 总结 综上所述,虽然两者都实现了相同的接口功能相似之处很多,但在具体应用层面还是各有千秋——前者凭借紧凑布局带来更好的缓存命中率进而提高迭代器遍历时的整体效能;后者依靠灵活机动特性适应那些侧重局部变动处理需求的应用环境之中[^10]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值