Java ArrayList2025年4月1日 | 阅读 21 分钟 ![]() Java 中的 ArrayList 是 Java 集合框架中的一个动态数组实现。它是一个大小可变的数组,当向其中添加更多元素时,它会自动增长。 ArrayList 来自 java.util 包,因其易用性和灵活性而广受欢迎。它们之所以灵活,是因为您无需在创建 ArrayList 时确定其大小,这与 Java 中的标准数组类似。因此,它比传统数组更灵活。它类似于 C++ 中的 Vector。 Java 中的 ArrayList 也可以包含重复元素。它实现了 List 接口,因此我们可以使用 List 接口的所有方法。ArrayList 在内部维护插入顺序。 它继承了 AbstractList 类并实现了 List 接口。 关于 Java ArrayList 类的重要注意事项是:
ArrayList 类的继承结构如上图所示,Java ArrayList 类继承了 AbstractList 类,该类实现了 List 接口。List 接口在其继承结构中继承了 Collection 和 Iterable 接口。 ArrayList 类声明让我们看看 java.util.ArrayList 类的声明。 public class ArrayList<E>: 引入了 ArrayList 类作为通用类,其中类型参数 E 是 ArrayList 中存储的元素的类型。类型参数 E 使 ArrayList 能够存储任何引用类型的对象。 extends AbstractList<E>: 表示 ArrayList 类是 AbstractList 类的子类。AbstractList 实现 List 接口的骨架方面,提供了其几乎所有方法。 implements List<E>: 表示 ArrayList 类实现了 List 接口。List 接口描述了列表的操作,并继承了 Collection 接口。 implements RandomAccess: 表示 ArrayList 类实现了 RandomAccess 标记接口。此接口是为提供对其元素的快速(常量时间)随机访问的类设置的标志。 implements Cloneable: 表明 ArrayList 类实现了 Cloneable 标记接口。此接口表示 ArrayList 实例可以使用 clone() 方法进行克隆。 implements Serializable: 这表明 ArrayList 类实现了 Serializable 标记接口。此接口使得 ArrayList 类的实例可以被序列化(转换为字节流)以进行存储或传输。 ArrayList 类的构造函数
ArrayList 类的方法
Java 非泛型与泛型集合在 JDK 1.5 之前,Java 集合框架是非泛型的,这意味着类型安全性无法保证,并且在从集合中检索元素时需要手动进行类型转换。 在这个非泛型 ArrayList 中,您可以添加任何类型的元素,编译器也不会强制执行类型安全。例如,您可以先添加一个 String,然后添加一个 Integer,而无需编译时检查。 随着 Java 5 (JDK 1.5) 中泛型的引入,集合框架变成了泛型的。泛型允许您在编译时指定集合可以容纳的元素类型,从而提供类型安全性并消除显式类型转换的需要。例如,创建泛型 ArrayList 的示例:让我们看看创建 Java 集合的新泛型示例。 在这个泛型 ArrayList 中,类型参数 Java ArrayList 示例示例编译并运行输出 [Mango, Apple, Banana, Grapes] 使用 Iterator 遍历 ArrayList在 Java 中,使用 Iterator 遍历 ArrayList 是一个常见的操作,它允许您按顺序遍历列表的元素。迭代器提供了一种安全高效的方式来访问集合中的元素,特别是当您想在迭代过程中执行删除元素等操作时。让我们来看一个使用 Iterator 接口遍历 ArrayList 元素的示例。 示例编译并运行输出 Mango Apple Banana Grapes 使用 For-each 循环遍历 ArrayList使用 for-each 循环(也称为增强 for 循环)遍历 ArrayList 提供了一种简洁易读的方式来按顺序访问列表中的元素。这种方法简化了代码,特别是在您只需要遍历元素而不需要索引或执行复杂操作时非常有用。让我们看一个使用 for-each 循环遍历 ArrayList 元素的示例。 示例编译并运行输出 Mango Apple Banana Grapes 获取和设置 ArrayList您可以使用 get() 和 set() 方法检索和修改 ArrayList。 使用 get() 方法
使用 set() 方法
示例编译并运行输出 Returning element: Apple Mango Dates Banana Grapes 如何对 ArrayList 进行排序?java.util 包提供了一个实用类 **Collections**,其中包含静态方法 sort()。使用 **Collections.sort()** 方法,我们可以轻松地对 ArrayList 进行排序。 示例编译并运行输出 Apple Banana Grapes Mango Sorting numbers... 1 11 21 51 遍历 Java 中集合元素的方法遍历集合元素有多种方法
通过其余方法遍历集合让我们看一个通过其他方式遍历 ArrayList 元素的示例 示例编译并运行输出 Traversing list through List Iterator: Ajay Ravi Vijay Ravi Traversing list through for loop: Ravi Vijay Ravi Ajay Traversing list through forEach() method: Ravi Vijay Ravi Ajay Traversing list through forEachRemaining() method: Ravi Vijay Ravi Ajay Java ArrayList 中的用户自定义类对象ArrayList 可以存储用户自定义类的对象,从而在管理自定义数据类型集合方面提供了灵活性和可扩展性。此功能允许开发人员创建根据其特定应用程序需求量身定制的集合。 在 ArrayList 中使用用户自定义类对象时,ArrayList 中的每个元素都代表用户自定义类的一个实例。例如,考虑一个 Student 类代表具有姓名、年龄和学号等属性的个人。我们可以创建一个 ArrayList 来存储 Sudent 类的实例 让我们看一个将 Student 类对象存储在 ArrayList 中的示例。 示例输出 101 Sonoo 23 102 Ravi 21 103 Hanumat 25 Java ArrayList 序列化和反序列化示例Java 中的序列化和反序列化是将对象转换为字节流以进行存储或传输,然后分别从这些字节流中重构对象的进程。此机制允许将对象保存到文件、通过网络发送或存储在数据库中。 让我们看一个序列化 ArrayList 对象然后对其进行反序列化的示例。 示例输出 [Ravi, Vijay, Ajay] Java ArrayList 添加元素的示例在这里,我们看到添加元素的各种方法。 示例输出 Initial list of elements: [] After invoking add(E e) method: [Ravi, Vijay, Ajay] After invoking add(int index, E element) method: [Ravi, Gaurav, Vijay, Ajay] After invoking addAll(Collection<? extends E> c) method: [Ravi, Gaurav, Vijay, Ajay, Sonoo, Hanumat] After invoking addAll(int index, Collection<? extends E> c) method: [Ravi, John, Rahul, Gaurav, Vijay, Ajay, Sonoo, Hanumat] Java ArrayList 删除元素的示例在这里,我们看到删除元素的各种方法。 示例输出 An initial list of elements: [Ravi, Vijay, Ajay, Anuj, Gaurav] After invoking remove(object) method: [Ravi, Ajay, Anuj, Gaurav] After invoking remove(index) method: [Ajay, Anuj, Gaurav] Updated list : [Ajay, Anuj, Gaurav, Ravi, Hanumat] After invoking removeAll() method: [Ajay, Anuj, Gaurav] After invoking removeIf() method: [Anuj, Gaurav] After invoking clear() method: [] Java ArrayList retainAll() 方法示例Java ArrayList 中的 retainAll() 方法用于仅保留 ArrayList 中也存在于另一个集合(通常是另一个 ArrayList)中的元素。换句话说,它会删除当前 ArrayList 中不存在于指定集合中的所有元素。 示例编译并运行输出 iterating the elements after retaining the elements of al2 Ravi Java ArrayList isEmpty() 方法示例Java ArrayList 中的 isEmpty() 方法用于检查 ArrayList 是否为空,即,如果 ArrayList 不包含任何元素,则返回 true,否则返回 false。 示例编译并运行输出 Is ArrayList Empty: true After Insertion Is ArrayList Empty: false Java ArrayList 示例:Book让我们看一个 ArrayList 示例,其中我们将书籍添加到列表中并打印所有书籍。 示例编译并运行输出 101 Let us C Yashwant Kanetkar BPB 8 102 Data Communications and Networking Forouzan Mc Graw Hill 4 103 Operating System Galvin Wiley 6 ArrayList 的大小和容量ArrayList 的大小和容量是初学者容易混淆的两个术语。ArrayList 通过添加或删除元素来处理可变大小的元素,使其在集合方面具有灵活性。ArrayList 的长度是指要存储在其中的元素数量,您可以通过调用 size() 方法来获取。添加或删除元素时,此大小会自动调整。 Array List 的容量是指在需要重新调整大小时它可以容纳的最大元素数量。最初,ArrayList 的容量由用于创建它的构造函数定义,或者在没有定义构造函数的情况下由默认容量定义。当 ArrayList 中的对象总数超过当前容量时,ArrayList 会自动重新分配并增加其容量以容纳更多对象,从而实现高效的存储和即时响应。可以使用 capacity() 方法检索 ArrayList 的大小。ArrayList 的大小和容量的逻辑在 ArrayList 和 Vector 类中是相同的。 让我们在这一节中通过一些例子来理解它。考虑以下代码片段。 示例编译并运行输出 The size of the array is: 0 解释: 输出是有意义的,因为我们还没有对 ArrayList 做任何事情。现在观察以下程序。 示例编译并运行输出 The size of the array is: 0 解释: 我们看到大小仍然是 0,原因是因为数字 10 代表容量而不是大小。事实上,大小代表数组中存在的元素总数。由于我们没有添加任何元素,因此两个程序中的 ArrayList 的大小都为零。 想象你有一个叫做 ArrayList 的盒子。这个盒子有一个叫做容量的特殊属性,它告诉你里面能装多少东西。假设这个盒子的容量是 10。 现在,你开始往这个盒子里放东西,比如玩具。每次放一个玩具进去,你都会检查盒子里的玩具数量(这叫做大小)是否等于容量。如果是,这意味着盒子满了,你需要一个更大的盒子来放更多的玩具。 所以,在你往盒子里放 10 个玩具之前,容量一直保持在 10。但是一旦你试图往里放第 11 个玩具,你就会发现盒子满了,你需要一个更大的盒子。在我们的例子中,由于盒子只能装 10 个玩具,你需要一个新的容量更大的盒子。 现在,请记住,有两种情况 在第一种情况下,你从一个可以装 10 个玩具的默认盒子开始。你没有指定容量;它只是默认的。 在第二种情况下,你明确地说:“我想要一个容量为 10 个玩具的盒子。”所以,一开始,你就得到了一个可以装 10 个玩具的盒子。 但在这两种情况下,过程都是相同的:你不断地添加玩具,如果盒子满了,你就会换一个更大的。 注意:没有标准的方法可以知道 ArrayList 的容量是如何增加的。事实上,容量增加的方式因 JDK 版本而异。因此,需要检查 JDK 中的容量增加代码是如何实现的。ArrayList 类中没有预定义的方法可以返回 ArrayList 的容量。因此,为了更好地理解,请使用 Vector 类的 capacity() 方法。ArrayList 和 Vector 类的大小和容量的逻辑是相同的。 ArrayList 的优点动态大小调整: ArrayList 在添加或删除元素时会自动调整大小;因此,无需手动调整大小。ArrayList 能够自动调整大小,使其能够处理各种数量的元素,而无需手动调整大小。 随机访问: ArrayList 通过索引确保常数时间访问元素,允许执行随机访问。这一优势使得 ArrayList 成为需要基于其顺序进行随机访问元素的最佳选择。 快速迭代: ArrayList 允许使用增强循环或迭代器高效地遍历其所有元素。这种能力很有优势,因为它使得可以无缝地按顺序处理列表中的每个元素。无论是使用循环还是迭代器,您都可以轻松地访问和操作 ArrayList 中的每个项目,而无需复杂的索引或遍历逻辑。这种简化的方法提高了代码的可读性并简化了操作,使 ArrayList 成为各种编程任务的通用且方便的数据结构。 多功能性: ArrayList 可以维护任何类型的对象,包括用户创建的类。这种多功能性使开发人员能够根据客户的独特需求设计解决方案,整合不同的数据类型和格式。 灵活性: ArrayList 提供了大量与修改、插入或放置元素相关的方法,从而确保了在操作记录方面的灵活性。它支持添加、删除、访问、编辑等功能,使数据管理简单顺畅。 泛型支持: 随着 Java 5 中泛型的出现,ArrayList 变得类型安全,您可以定义它包含的元素类型。这改进了编译时类型检查并保证了类型安全,从而防止了运行时错误。 与 Java 集合框架集成: ArrayList 是 Java 集合框架的一部分,该框架定义了用于组织对象集合的统一架构。模块集成提供了与框架内其他排序模块和算法的兼容性。 ArrayList 的缺点动态大小调整开销: ArrayList 的动态大小调整功能虽然有利于容纳添加或删除的元素,但会带来性能开销。随着内部数组动态地扩展或收缩,频繁的大小调整操作(尤其是在大型 ArrayList 中)会产生明显的开销。每次大小调整都涉及分配新内存、复制现有元素以及释放旧数组,这会消耗计算资源和时间。因此,过度的调整大小会影响程序效率,导致执行时间变慢。因此,虽然 ArrayList 的灵活性是有利的,但开发人员必须仔细管理大小调整操作以减轻性能损失,确保处理大型或频繁修改的 ArrayList 的应用程序获得最佳性能。 内存浪费: ArrayList 以块的形式分配内存,并且可能会分配比所需更多的内存来满足未来的增长。这可能会导致内存浪费,尤其是在 ArrayList 容量很大但只包含几个元素的情况下。 低效的插入和删除: ArrayList 的插入和删除操作效率低下,尤其是在列表的中间或开头。这种低效率是由于在添加新元素或删除元素时移动 ArrayList 中的元素所致。 不适合原始类型: ArrayList 只能存储对象,不能直接存储原始数据类型。在存储原始类型时,需要 Integer、Double 等包装类,这可能会消耗更多内存并导致额外的装箱/拆箱开销。 非线程安全: ArrayList 是非同步的,并且在设计上不是线程安全的。多个线程可以同时对 ArrayList 进行并发修改,这可能导致不可预测或损坏的数据。必须使用外部同步块来处理同步,或者使用 Vector 或 CopyOnWriteArrayList 作为线程安全的替代方案。 大型集合性能受限: 然而,对于极大的集合,ArrayList 在插入、删除或搜索操作方面可能不如 LinkedList 和 HashSet 等其他数据结构有效。替代数据结构可能更适用于特定情况。 Java ArrayList 选择题1. 以下哪个接口是 Java ArrayList 类直接实现的?
答案:C 解释: ArrayList 类直接实现了 List 接口。此接口允许有序集合,并提供操作列表大小和元素的方法。Set、Queue 和 Map 接口不是 ArrayList 直接实现的。 2. 当从 ArrayList 中删除元素时,以下哪项最能描述对剩余元素的影响?
答案:C 解释: 当从 ArrayList 中删除元素时,所有后续元素都会向左移动以填补被删除元素造成的空隙。这可能导致删除操作的时间复杂度为 O(n),其中 n 是被删除元素后的元素数量。 3. Java 中 ArrayList 的初始默认容量是多少?
答案:B 解释: 当不指定容量创建 ArrayList 时,默认初始容量为 10。随着向列表中添加元素,此容量可以动态增加。 4. 使用哪种方法可以确保 ArrayList 实例至少包含指定数量的元素?
答案:B 解释: ensureCapacity(int minCapacity) 方法用于增加 ArrayList 实例的容量,以确保它可以容纳至少由 minCapacity 指定的元素数量。这有助于在预期添加大量元素时最大限度地减少大小调整操作的数量。 5. Java ArrayList 在其容量需要增加时如何处理这种情况?
答案:C 解释: 当 ArrayList 需要更多容量时,它会创建一个具有更大容量的新数组(通常是当前容量的 1.5 倍或更多),然后将现有元素复制到这个新数组中。这种大小调整机制允许 ArrayList 有效地处理动态增长。 下一主题Java LinkedList |
我们请求您订阅我们的新闻通讯以获取最新更新。