杰瑞科技汇

ArrayList与List有何区别?

  • List 是一个接口,它定义了一个列表应该具备的行为规范(add(), get(), size() 等)。
  • ArrayList 是一个具体的类,它实现了 List 接口,并提供了一种基于动态数组的数据结构来存储数据。

详细对比

为了更清晰地理解,我们从几个维度进行详细对比。

ArrayList与List有何区别?-图1
(图片来源网络,侵删)
特性 List ArrayList
本质 接口
定义 java.util.List java.util.ArrayList
作用 定义一个有序的、允许重复元素的集合的蓝图契约 List 接口最常用、最标准的实现类之一。
实例化 不能被直接实例化(不能 new List())。 可以被直接实例化(new ArrayList())。
多态 支持,可以声明为 List 类型,但实例化为 ArrayList 或其他实现类。 支持,可以被声明为 List 接口类型,也可以声明为其本身的 ArrayList 类型。
数据结构 不涉及,它只定义行为。 动态数组,内部使用一个数组来存储元素,当容量不足时,会自动创建一个更大的数组并复制旧数组的内容。
性能特点 不涉及,取决于其具体的实现类。 随机访问快get(int index) 时间复杂度为 O(1)。
尾部添加/删除较快add(E e)remove(size()-1) 均摊时间复杂度为 O(1)。
中间插入/删除慢add(int index, E element)remove(int index) 时间复杂度为 O(n),因为需要移动大量元素。
是否允许 null 取决于实现类。 允许,可以存储多个 null 值。
是否允许重复 允许 允许

核心关系:接口与实现

ListArrayList 的关系是 Java 中 “接口-实现” 经典模式的体现。

// List 是一个接口,它像一个“菜单”,列出了所有可以做的事情
public interface List<E> extends Collection<E> {
    // ... 方法列表: add, get, remove, size, iterator 等 ...
}
// ArrayList 是一个类,它实现了这个“菜单”,并且提供了具体的做法
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    // ... 内部实现细节 ...
}

这就好比:

  • List 是“汽车”这个概念,它规定了汽车应该有轮子、能载人、能行驶。
  • ArrayList 是“丰田卡罗拉”这款具体的汽车,它实现了“汽车”的所有功能,并且有自己特定的发动机和底盘。

代码示例:如何使用?

在实际开发中,我们强烈推荐使用接口来声明,用实现类来实例化,这样可以提高代码的灵活性和可维护性。

推荐的方式(面向接口编程)

import java.util.ArrayList;
import java.util.List;
public class RecommendedWay {
    public static void main(String[] args) {
        // 声明为 List 接口类型,但实例化为 ArrayList
        // 这使得未来如果需要换成 LinkedList,只需修改这一行,其他代码无需改动
        List<String> names = new ArrayList<>();
        // 添加元素
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        // 获取元素
        String firstPerson = names.get(0); // "Alice"
        System.out.println("First person: " + firstPerson);
        // 获取大小
        System.out.println("List size: " + names.size()); // 3
        // 遍历
        for (String name : names) {
            System.out.println(name);
        }
    }
}

不推荐的方式(面向具体类编程)

这种方式虽然也能工作,但会降低代码的灵活性。

ArrayList与List有何区别?-图2
(图片来源网络,侵删)
import java.util.ArrayList;
public class NotRecommendedWay {
    public static void main(String[] args) {
        // 直接声明和实例化为 ArrayList
        ArrayList<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        // 如果将来因为性能需求(比如频繁在头部增删)需要换成 LinkedList,
        // 你需要修改所有声明为 `ArrayList` 的地方,非常繁琐。
        // List<String> names = new LinkedList<>(); // 需要改动很多地方
    }
}

何时选择 ArrayList

ArrayList 是最通用的列表实现,但在以下场景下它表现出色:

  1. 需要频繁进行随机访问:如果你经常需要通过索引(list.get(i))来获取元素,ArrayList 是最佳选择,因为它的时间复杂度是 O(1)。
  2. 主要在列表尾部进行增删操作:如果你只是简单地往列表末尾添加元素或从末尾删除元素,ArrayList 的性能也很好(均摊 O(1))。
  3. 数据量相对固定,或不需要频繁在中间插入/删除:如果你不需要在列表的中间位置频繁地插入或删除元素,ArrayList 的性能是可以接受的。

何时选择其他 List 实现?

虽然问题只问了 ArrayList,但了解它的“兄弟”有助于你做出更好的选择:

  • LinkedList

    • 数据结构:双向链表。
    • 优点:在中间或头部进行增删操作非常快(O(1)),因为它只需要修改前后节点的指针即可。
    • 缺点:随机访问很慢(O(n)),因为它必须从头或尾开始遍历。
    • 适用场景:当你需要频繁在列表的任何位置(尤其是头部)进行增删操作,且不关心随机访问性能时。
  • Vector

    ArrayList与List有何区别?-图3
    (图片来源网络,侵删)
    • 数据结构:也是动态数组,与 ArrayList 类似。
    • 关键区别Vector线程安全的,它的所有方法都带有 synchronized 关键字。
    • 缺点:因为同步开销,性能比 ArrayList 差。
    • 适用场景:在现代 Java 开发中,很少直接使用 Vector,如果需要线程安全的列表,通常使用 Collections.synchronizedList(new ArrayList<>()) 或者 CopyOnWriteArrayList

List ArrayList
角色 接口 (Interface) 实现类 (Implementation)
好比 菜单、蓝图 一道具体的菜、一辆具体的汽车
使用 用于声明变量,定义类型 用于实例化对象,创建实例
核心原则 定义“做什么” 定义“怎么做”

记住这个黄金法则:

永远面向接口编程(Use the interface as the type)。

也就是说,在你的方法参数、返回值和变量声明中,尽可能地使用 List,而不是 ArrayList,只有在创建对象实例时,才指定具体的实现类,如 new ArrayList<>(),这是编写高质量、可扩展 Java 代码的关键实践。

分享:
扫描分享到社交APP
上一篇
下一篇