章
目
录
在 Java 编程中,数组和数组列表是两种基本数据结构,通常用于存储元素集合。尽管两者用于相同的目的,但它们独特的特性显着影响应用程序的性能和灵活性。
本 Java 教程探讨了数组和数组列表的重要特性、它们各自的优点和缺点,以及在需要时促进无缝转换的两种结构之间转换的不同技术。
一、简介
在Java中,ArrayList是集合框架的一部分,是可调整大小的数组数据结构的实现。这意味着 arraylist 内部维护了一个在需要时动态增长或收缩的数组。
1.1. Java 数组
数组是一种固定大小的数据结构,它将相同数据类型的元素存储在连续的内存位置中。数组中的每个元素都由索引或位置标识,第一个元素从 0 开始。
Java 中的数组与其他编程语言中的数组相同。通常,数组具有以下特性:
- 数组始终存储相同数据类型的元素。数组类型在初始化时声明。
- 整数数组只能存储整数值。Java 编译器不允许在此整数数组中存储字符串。
- 仅使用索引来访问数组中的每个元素。没有其他方法可以访问数组的元素。
- 数组大小始终是固定的,无法更改。要存储更多数组大小的元素,我们必须创建一个新数组并将元素从旧数组复制到新数组中。当我们尝试添加超过其大小时,它会抛出 ArrayIndexOutOfBoundsException。
例如,以下数组的内部存储器表示如下:
int[] a = new int[5];
a[0] = 1;
a[1] = 2;
a[2] = 4;
a[3] = 8;
a[4] = 16;
数组的大小是固定的,这意味着数组一旦创建,其大小就无法更改。使用其相应的索引来访问数组中的每个元素。
for(int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
1.2. Java 数组列表
ArrayList类是Java 集合框架的一部分,并实现List接口。与数组不同,ArrayList可以随着元素的添加或删除而动态增长或收缩。
可以在数组列表中存储多种类型的元素,但通常不鼓励这样做,因为当我们从数组中获取元素时,它可能会在运行时导致ClassCastException 。为了强制类型安全,使用泛型来声明数组列表中存储的元素的类型。
List<Integer> arraylist = new ArrayList<>();
arraylist.add(1); // allowed
//arraylist.add("one"); // NOT allowed
除了使用 for 循环进行顺序访问之外,数组列表还允许使用ListIterator等迭代器来迭代元素。当我们使用迭代器并使用迭代器修改集合时,它不会通过ConcurrentModificationException。
List<Integer> arraylist = new ArrayList<>();
arraylist.add(1);
arraylist.add(2);
arraylist.add(3);
//1 - using foreach loop
arraylist.forEach(System.out::println);
//2 - using iterator
ListIterator<Integer> listIterator = arraylist.listIterator();
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
2. Java中Array和ArrayList的区别
下表总结了数组和数组列表之间的比较。它根据性能、易用性和用例对两种数据结构进行了比较。
特征 | 数组 | 数组列表 |
---|---|---|
固定大小与动态调整大小 | 初始化时分配固定大小 | 添加或删除元素时动态调整大小 |
内存管理和效率 | 如果数组大小超过其实际保存的元素数,固定大小可能会导致内存浪费。 | 动态调整大小会因优化内存使用而产生轻微的性能开销。 |
语法和易用性 | 用于初始化、添加、删除和更新操作的直接语法。 | 使用 Collections API 方法的更直观、更方便的工作方式。 |
表现 | 对于读/写操作,由于使用索引直接访问元素,数组通常更快。 对于需要调整大小的写入操作,数组列表的性能优于数组。 |
除了需要调整大小的写入操作外,数组列表的性能比数组差。 |
类型安全 | 数组的类型安全性有限,并允许在同一数组中存储任何类型的元素。 | ArrayList 通过使用泛型提供更好的类型安全性,确保只能存储特定类型的元素。 |
最适合用于 | 当需要固定大小的集合并且内存效率至关重要时,请使用数组。 | ArrayList 最适合用于小型集合,其中便利性优先于小且可以忽略不计的性能提升。 |
3. 将数组转换为ArrayList
将数组转换为ArrayList最直接的方法是使用Arrays.asList()方法创建List
数组视图,然后使用ArrayList构造函数创建一个新的ArrayList。这有效地将数组转换为ArrayList。
String[] array = {"apple", "banana", "cherry"};
ArrayList<String> arrayList = new ArrayList<>(Arrays.asList(array));
或者,我们还可以使用Java 8 流来迭代数组元素并将它们收集到新的ArrayList中。它使我们有机会在将数组的每个元素收集到列表中之前对它们执行附加操作。
ArrayList<String> arrayList = Arrays.stream(array)
//additional actions
.collect(Collectors.toCollection(ArrayList::new));
4.将ArrayList转换为数组
将 arraylist 转换为数组的最简单解决方案是使用 ArrayList.toArray()方法,该数组以正确的顺序包含列表中的所有元素。toArray ()返回一个Object[]类型的数组,因此您需要提供所需数组的类型作为toArray()方法的参数。
新数组的大小由ArrayList的大小决定。
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("apple");
arrayList.add("banana");
arrayList.add("cherry");
String[] array = arrayList.toArray(new String[arrayList.size()]);
5. 最佳实践和建议
ArrayList 和数组两者的用途几乎相似,并且各有优势。以下建议应该帮助我们缩小应用程序的范围并选择正确的数据结构。
5.1. 调整大小操作的频率
如果由于特定需求需要频繁调整数组大小,建议使用ArrayList。调整大小操作的内部处理消除了应用程序代码的复杂性,并提供了与手动执行几乎相似的性能增益。
5.2. 可量化的绩效收益
如果性能增益没有显着提高,则始终建议选择数组列表而不是数组。ArrayList 消除了复杂性,使代码更具可读性,并为小型集合提供几乎相似的性能。
衡量性能提升的最佳方法是使用任何工具(例如JMH)进行测量。
5.3. 基元与包装对象
数组可以直接使用基元类型,而数组列表可以使用对象,即本例中的包装类。如果在处理应用程序中的两种类型时需要在这两种类型之间进行不断的转换,那么最好使用数组,因为它们将通过删除不必要的类型转换来简化代码,并因此获得轻微的性能提升。
int[] array = new int[10];
//Creating arraylist for 'int' type is not possible. We must create arraylist of type 'Integer'
ArrayList<Integer> arraylist = new ArrayList<>();
5.4. 与其他集合类型的互操作性
ArrayList是 Java 集合框架的一部分,因此可以与其他类型(例如Map、Set等)无缝协作。使用数组会引入不必要的额外步骤来在其他集合类型之间进行转换。
使用数组列表将减少此类转换,从而生成更具可读性和简洁性的代码。
六,结论
总之,Java 开发最佳实践更经常推荐使用ArrayList和其他内置集合类,因为它们的灵活性、易用性以及对于中小型集合的类似性能。
然而,在某些情况下,数组可能更合适,特别是当性能或内存效率是主要考虑因素时。