Java容器深入浅出之List、ListIterator和ArrayList

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: List是Collection接口的子接口,表示的是一种有序的、可重复元素的集合。List接口的主要实现类ArrayList和Vector,底层都是维护了一套动态的,可扩展长度的Object[]数组,通过initialCapacity参数来动态地调整长度。

List是Collection接口的子接口,表示的是一种有序的、可重复元素的集合。

List接口的主要实现类ArrayList和Vector,底层都是维护了一套动态的,可扩展长度的Object[]数组,通过initialCapacity参数来动态地调整长度。因此,相比较父接口Collection所提供的公共增删改方法,List接口及实现类也定义了通过索引来增删查改元素,或者基于元素查找索引的方法。更一般地,ArrayList中的元素可以为null。

List及List新增的ListIterator接口

List接口的定义方法如下

 1 public class TestList {
 2 
 3     @SuppressWarnings("unlikely-arg-type")
 4     public static void main(String[] args) {
 5         
 6         List<String> books = new ArrayList<>();
 7         //List集合添加元素的顺序是有序的
 8         books.add(new String("资本论"));
 9         books.add(new String("***宣言"));
10         books.add(new String("家庭私有制和国家的起源"));
11         System.out.println(books);
12         //add和addAll分别在指定索引处添加元素或另一个集合
13         books.add(1, "德意志意识形态");
14         books.forEach(str -> System.out.println(str));
15         //使用Lambda表达式对List进行排序
16         books.sort((o1, o2) -> (o1.length() - o2.length()));
17         System.out.println(books);
18         //删除指定索引的元素
19         books.remove(2);
20         System.out.println(books);
21         //通过指定索引返回元素(==根据HashCode来判断,此处返回false)
22         System.out.println(books.get(0) ==new String("资本论"));
23         //通过indexOf来返回指定元素所在的索引位置
24         //indexOf通过元素的equals方法来判断, 只要是true就返回对应的索引
25         System.out.println(books.indexOf(new String("德意志意识形态")));
26         //通过索引改变元素
27         books.set(1, new String("神圣家族"));
28         //返回子集合[1,3), 不改变原集合
29         System.out.println(books.subList(1, 3));
30         
31         //使用Lambda表达式使用每个字符的长度替代原集合的元素
32         books.replaceAll(ele -> ele.length() + "");
33         //因为A对象equals方法恒返回true,所以集合会在第一次比较中直接删除第一个元素
34         books.remove(new A());
35         System.out.println(books);
36         //同样的,继续删除第一个元素
37         books.remove(new A());
38         System.out.println(books.size());
39         
40     }
41 
42 }
43 
44 class A{
45     //定义A类对象的equals方法恒返回true
46     public boolean equals(Object obj) {
47         return true;
48     }
49 }

与Set集合不同,List集合新增了一个继承Iterator接口的子接口ListIterator接口,可以实现反向迭代和增加元素的功能。

 1 /*
 2  * 与Collection集合的Iterator接口不同, List额外提供一个ListIterator接口(继承了Iterator接口), 增加了如下三个方法:
 3  * 1. hasPrevious():是否还有上一个元素
 4  * 2. previous():返回上一个元素
 5  * 3. add():增加一个元素
 6  */
 7 public class ListIteratorTest {
 8 
 9     public static void main(String[] args) {
10         
11         String[] books = {
12                 "资本论","德意志意识形态","***宣言"
13         };
14         List<String> booksList = new ArrayList<>();
15         for(int i=0; i<books.length;i++) {
16             booksList.add(books[i]);
17         }
18         ListIterator<String> lit = booksList.listIterator();
19         System.out.println("====下面开始正向迭代====");
20         while(lit.hasNext()) {
21             System.out.println(lit.next());
22             lit.add("----分隔符----");
23         }
24         System.out.println("====下面开始反向迭代====");
25         while(lit.hasPrevious()) {
26             System.out.println(lit.previous());
27         }
28         
29     }
30 
31 }

ArrayList和Vector

如前所述,ArrayList和Vector底层维护了一个动态可变的对象数组。如果创建对象时不指定容量值,会有一个默认的数组长度10。更一般地,可以通过在创建对象时指定容量值:

1. void ensureCapacity(int minCapacity):将List集合数组长度增加到minCapacity。如可提前知道元素个数,可以赋值长度,以减少频繁扩容所带来的性能开销。

2. void trimToSize():调整数组长度至当前元素的个数,以节省空间。

ArrayList与Vector相比较,需要注意以下几点:

1. ArrayList是线程不安全的,因此性能较高;Vector是线程安全的,但性能较差;后面的博文会介绍如果通过Collection提供的工具类,使ArrayList线程安全。

2. Vector及其子类Stack,是非常古旧的Java集合,并不建议使用。Stack子类所实现的栈功能,也可以通过ArrayDeque来实现。

固定长度的List

数组的工具类Arrays自带一个asList(Object... o)方法,可以将数组或指定数量的对象转换为List,不过需要注意一点:

该类是Arrays类的内部类ArrayList的实例,是固定长度的,相当于数组,只能用于遍历,不能增加和删除里面的元素。

 1 public class TestArrayList {
 2 
 3     public static void main(String[] args) {
 4         
 5         List<String> list = Arrays.asList("AA", "BB", "CC");
 6         //显示类的类型为java.util.Arrays$ArrayList
 7         System.out.println(list.getClass());
 8         
 9         list.forEach(System.out::println);
10         //以下会抛出运行时异常java.lang.UnsupportedOperationException
11         list.add("DD");
12 
13     }
14 
15 }

线性表的性能选择

一般来说,基于数组的ArrayList在随机访问中性能较好;基于链表的LinkedList在插入、删除中性能较好。但在一般使用中,ArrayList总体性能占优,因此使用非常广泛。

1. 如果需要遍历List元素,ArrayList建议使用随机访问方法;对于LinkedList,建议使用Iterator迭代器

2. 如果需要经常插入、删除大量数据的List集合,可以考虑使用LinkedList

目录
相关文章
|
4月前
|
人工智能 安全 JavaScript
Java ArrayList:动态数组
本文探讨Java中的数组,对比C/C++、JS/PHP/Python等语言的数组特性。文章分析了Java数组的定义、创建方式及其规范,指出其优缺点。Java数组作为引用类型,在堆上分配内存,支持动态大小,避免了C/C++中裸数组的常见问题(如越界访问)。然而,Java数组也存在性能瓶颈和设计缺陷,例如运行时的安全检查影响速度,无法创建超大数组或泛型数组,且多线程场景下缺乏同步机制。作者建议在实际开发中用集合替代数组以规避这些问题。
107 1
|
2月前
|
Java 索引
Java ArrayList中的常见删除操作及方法详解。
通过这些方法,Java `ArrayList` 提供了灵活而强大的操作来处理元素的移除,这些方法能够满足不同场景下的需求。
288 30
|
6月前
|
人工智能 Java
Java 中数组Array和列表List的转换
本文介绍了数组与列表之间的相互转换方法,主要包括三部分:1)使用`Collections.addAll()`方法将数组转为列表,适用于引用类型,效率较高;2)通过`new ArrayList&lt;&gt;()`构造器结合`Arrays.asList()`实现类似功能;3)利用JDK8的`Stream`流式计算,支持基本数据类型数组的转换。此外,还详细讲解了列表转数组的方法,如借助`Stream`实现不同类型数组间的转换,并附带代码示例与执行结果,帮助读者深入理解两种数据结构的互转技巧。
264 1
Java 中数组Array和列表List的转换
|
7月前
|
存储 安全 算法
Java容器及其常用方法汇总
Java Collections框架提供了丰富的接口和实现类,用于管理和操作集合数据。
Java容器及其常用方法汇总
|
10月前
|
Java 索引 容器
Java ArrayList扩容的原理
Java 的 `ArrayList` 是基于数组实现的动态集合。初始时,`ArrayList` 底层创建一个空数组 `elementData`,并设置 `size` 为 0。当首次添加元素时,会调用 `grow` 方法将数组扩容至默认容量 10。之后每次添加元素时,如果当前数组已满,则会再次调用 `grow` 方法进行扩容。扩容规则为:首次扩容至 10,后续扩容至原数组长度的 1.5 倍或根据实际需求扩容。例如,当需要一次性添加 100 个元素时,会直接扩容至 110 而不是 15。
298 4
Java ArrayList扩容的原理
|
10月前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
10月前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
|
11月前
|
安全 Java 程序员
深入Java集合框架:解密List的Fail-Fast与Fail-Safe机制
本文介绍了 Java 中 List 的遍历和删除操作,重点讨论了快速失败(fail-fast)和安全失败(fail-safe)机制。通过普通 for 循环、迭代器和 foreach 循环的对比,详细解释了各种方法的优缺点及适用场景,特别是在多线程环境下的表现。最后推荐了适合高并发场景的 fail-safe 容器,如 CopyOnWriteArrayList 和 ConcurrentHashMap。
193 5
|
11月前
|
Java 程序员 编译器
Java|如何正确地在遍历 List 时删除元素
从源码分析如何正确地在遍历 List 时删除元素。为什么有的写法会导致异常,而另一些不会。
240 3
|
11月前
|
Java 程序员
Java|List.subList 踩坑小记
不应该仅凭印象和猜测,就开始使用一个方法,至少花一分钟认真读完它的官方注释文档。
166 1