Contents

Java中数组简介

1. 简介

在本教程中,我们将深入探讨 Java 语言中的一个核心概念——数组。 我们将首先了解什么是数组,然后了解如何使用它们;总的来说,我们将介绍如何:

  • 开始使用数组
  • 读取和写入数组元素
  • 循环数组
  • 将数组转换为其他对象,如ListStreams
  • 排序、搜索和组合数组

2. 什么是数组?

首先,我们需要定义什么是数组?根据Java 文档 ,数组是包含固定数量的相同类型值的对象。数组的元素是索引的,这意味着我们可以使用数字(称为index)访问它们。

我们可以将数组视为单元格的编号列表,每个单元格都是一个保存值的变量。在 Java 中,编号从 0 开始。

有原始类型数组和对象类型数组。这意味着我们可以使用int、float、boolean的数组……但也可以使用String、Object和自定义类型的数组。

3. 设置数组

现在数组已经定义好了,让我们深入了解它们的用法。

我们将涵盖很多教我们如何使用数组的主题。我们将学习一些基础知识,例如如何声明和初始化数组,但我们还将涵盖更高级的主题,例如排序和搜索数组。

让我们首先进行声明和初始化。

3.1. 声明

我们将从声明开始。在 Java 中有两种声明数组的方法:

int[] anArray;

或者:

int anOtherArray[];

前者比后者应用更广泛

3.2. 初始化

现在是时候看看如何初始化数组了。同样有多种方法可以初始化一个数组。我们将在这里看到主要的,但本文 将详细介绍数组初始化。

让我们从一个简单的方法开始:

int[] anArray = new int[10];

通过使用这种方法,我们初始化了一个包含十个int元素的数组。请注意,我们需要指定数组的大小。

使用此方法时,我们将每个元素初始化为其默认值,此处为 0。**初始化Object数组时,元素默认为null

我们现在将看到另一种方式,使我们可以在创建数组时直接为数组设置值:

int[] anArray = new int[] {1, 2, 3, 4, 5};

在这里,我们初始化了一个包含数字 1 到 5 的五元素数组。使用此方法时,我们不需要指定数组的长度,它是然后在大括号之间声明的元素数。

4. 访问元素

现在让我们看看如何访问数组的元素。我们可以通过要求数组单元位置来实现这一点。 例如,这个小代码片段将打印 10 到控制台:

anArray[0] = 10;
System.out.println(anArray[0]);

请注意我们如何使用索引来访问数组单元格。括号内的数字是我们要访问的数组的具体位置。

访问单元格时,如果传递的索引为负数或超出最后一个单元格,Java 将抛出ArrayIndexOutOfBoundException

我们应该注意不要使用负索引,或者大于或等于数组大小的索引

5. 遍历数组

逐个访问元素可能很有用,但我们可能希望遍历数组。让我们看看如何实现这一目标。

第一种方法是使用 for循环:

int[] anArray = new int[] {1, 2, 3, 4, 5};
for (int i = 0; i < anArray.length; i++) {
    System.out.println(anArray[i]);
}

这应该将数字 1 到 5 打印到控制台。正如我们所见,我们利用了length属性。这是一个公共属性,为我们提供了数组的大小。

当然,也可以使用其他循环机制,例如whiledo while。但是,对于 Java 集合,可以使用foreach循环遍历数组:

int[] anArray = new int[] {1, 2, 3, 4, 5};
for (int element : anArray) {
    System.out.println(element);
}

这个例子和前一个例子是等价的,但是我们去掉了索引样板代码。在以下 情况下,foreach循环是一个选项:

  • 我们不需要修改数组(将另一个值放入元素中不会修改数组中的元素)
  • 我们不需要索引来做其他事情

6. 可变参数

我们已经介绍了创建和操作数组的基础知识。现在,我们将深入探讨更高级的主题,从varargs开始。提醒一下,varargs用于将任意数量的参数传递给方法:

void varargsMethod(String... varargs) {}

此方法可以采用从 0 到任意数量的 String参数。 可以在 此处找到涵盖 varargs的文章。

这里我们要知道的是,在方法体内部,一个varargs 参数变成了一个数组。但是,**我们也可以直接传递一个数组作为参数。**让我们看看如何通过重用上面声明的示例方法:

String[] anArray = new String[] {"Milk", "Tomato", "Chips"};
varargsMethod(anArray);

行为将与以下内容相同:

varargsMethod("Milk", "Tomato", "Chips");

7. 将数组转换为列表

数组很棒,但有时处理 List会更方便。我们将在这里看到如何将数组转换为 List

我们将首先以幼稚的方式进行,通过创建一个空列表并遍历数组以将其元素添加到列表中:

int[] anArray = new int[] {1, 2, 3, 4, 5};
List<Integer> aList = new ArrayList<>();
for (int element : anArray) {
    aList.add(element);
}

但是还有另一种方式,更简洁一点:

Integer[] anArray = new Integer[] {1, 2, 3, 4, 5};
List<Integer> aList = Arrays.asList(anArray);

**静态方法 Arrays.asList接受一个可变参数并使用传递的值创建一个列表。**不幸的是,这种方法有一些缺点:

  • 不可能使用原始类型数组
  • 我们无法从创建的列表中添加或删除元素,因为它会抛出 UnsupportedOperationException

8. 从数组到流

我们现在可以将数组转换为列表,但从 Java 8 开始,我们可以访问Stream API  ,我们可能希望将数组转换为 Stream。Java 为我们提供了 Arrays.stream 方法:

String[] anArray = new String[] {"Milk", "Tomato", "Chips"};
Stream<String> aStream = Arrays.stream(anArray);

Object 数组传递给方法时,它将返回匹配类型的 Stream(例如 Stream<Integer>用于Integer数组 )。传递原始数据时,它将返回相应的原始数据 Stream

也可以仅在数组的子集上创建流:

Stream<String> anotherStream = Arrays.stream(anArray, 1, 3);

这将创建一个 只有“Tomato”和“Chips”字符串的Stream<String>  (第一个索引是包含的,而第二个是排除的)。

9. 排序数组

现在让我们看看如何对数组进行排序,即按特定顺序重新排列其元素。Arrays类 为我们提供了 sort 方法。 有点像 stream方法, sort有很多重载。

有重载需要排序:

  • 原始类型数组:按升序排序
  • Object数组(那些 Object必须实现 Comparable接口):按照自然顺序排序(依赖于 Comparable 中的 compareTo方法)
  • 泛型数组:根据给定的 Comparator

此外,可以只对数组的特定部分进行排序(将开始和结束索引传递给方法)。

sort方法 背后的算法 分别是原始数组和其他数组的快速排序和合并排序。

让我们通过一些例子来看看这一切是如何工作的:

int[] anArray = new int[] {5, 2, 1, 4, 8};
Arrays.sort(anArray); // anArray is now {1, 2, 4, 5, 8}
Integer[] anotherArray = new Integer[] {5, 2, 1, 4, 8};
Arrays.sort(anotherArray); // anotherArray is now {1, 2, 4, 5, 8}
String[] yetAnotherArray = new String[] {"A", "E", "Z", "B", "C"};
Arrays.sort(yetAnotherArray, 1, 3, 
  Comparator.comparing(String::toString).reversed()); // yetAnotherArray is now {"A", "Z", "E", "B", "C"}

10. 在数组中搜索

搜索数组非常简单,我们可以遍历数组并在数组元素中搜索我们的元素:

int[] anArray = new int[] {5, 2, 1, 4, 8};
for (int i = 0; i < anArray.length; i++) {
    if (anArray[i] == 4) {
        System.out.println("Found at index " + i);
        break;
    }
}

在这里,我们搜索了数字 4,并在索引 3 处找到了它。

如果我们有一个排序数组,我们可以使用另一种解决方案:二分查找。本文 解释了二分查找的原理。

**幸运的是,Java 为我们提供了 Arrays.binarySearch方法。**我们必须给它一个数组和一个要搜索的元素。

在泛型数组的情况下,我们还必须首先为其提供 用于对数组进行排序的比较器。再次有可能在数组的子集上调用该方法。

让我们看一个二进制搜索方法使用的例子:

int[] anArray = new int[] {1, 2, 3, 4, 5};
int index = Arrays.binarySearch(anArray, 4);
System.out.println("Found at index " + index);

由于我们将数字 4 存储在第四个单元格中,这将返回索引 3 作为结果。请注意,我们使用了一个已经排序的数组。

11. 连接数组

最后,让我们看看如何连接两个数组。这个想法是创建一个数组,其长度是要连接的两个数组的总和。之后,我们必须添加第一个元素,然后添加第二个元素

int[] anArray = new int[] {5, 2, 1, 4, 8};
int[] anotherArray = new int[] {10, 4, 9, 11, 2};
int[] resultArray = new int[anArray.length + anotherArray.length];
for (int i = 0; i < resultArray.length; i++) {
    resultArray[i] = (i < anArray.length ? anArray[i] : anotherArray[i - anArray.length]);
}

正如我们所看到的,当索引仍然小于第一个数组长度时,我们从该数组中添加元素。然后我们从第二个添加元素。我们可以使用 Arrays.setAll方法来避免编写循环:

int[] anArray = new int[] {5, 2, 1, 4, 8};
int[] anotherArray = new int[] {10, 4, 9, 11, 2};
int[] resultArray = new int[anArray.length + anotherArray.length];
Arrays.setAll(resultArray, i -> (i < anArray.length ? anArray[i] : anotherArray[i - anArray.length]));

此方法将根据给定函数设置所有数组元素。此函数将索引与结果相关联。

这是合并到数组的第三个选项:System.arraycopy。此方法采用源array、源位置、目标array、目标位置和定义要复制的元素数量的int

System.arraycopy(anArray, 0, resultArray, 0, anArray.length);
System.arraycopy(anotherArray, 0, resultArray, anArray.length, anotherArray.length);

正如我们所看到的,我们复制了第一个数组,然后是第二个(在第一个的最后一个元素之后)。