概述

在本教程中,我们将深入研究Java语言中的一个核心概念——数组。

我们先看看什么是数组,然后再看看如何使用它们;

  • 数组入门
  • 读写数组元素
  • 数组上的循环
  • 将数组转换为其他对象,如ListStreams
  • 数组的排序、搜索和组合

什么是数组

首先,我们了解什么是数组?

根据Java文档,数组是包含固定数量的相同类型的值。数组的元素被索引,这意味着我们可以用数字(索引)访问它们。

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

有基本类型数组和对象类型数组。这意味着我们可以使用intfloatboolean等类型的数组,也可以使用StringObject和自定义类型的数组。

数组用法

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

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

首先是声明和初始化。

声明

在Java中声明数组有两种方法:

int[] anArray;
int anOtherArray[];
前者比后者使用得更广泛, 建议使用前者

初始化

现在我们来看看如何初始化数组。同样,初始化数组有多种方法。我们将在这里看到主要的方法,但是本文将详细讨论数组初始化。

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

int[] anArray = new int[10];

通过使用这个方法,我们初始化了一个由10个int元素组成的数组。

注意,我们需要指定数组的大小。

使用此方法时,我们将每个元素初始化为其默认值,这里为0。初始化对象数组时,元素默认为空。

现在我们将看到另一种方法,使我们有可能设置值的数组直接创建时:

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

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

访问元素

现在让我们看看如何访问数组的元素。我们可以通过要求数组单元格位置来实现这一点。

例如,这一小段代码将打印10到控制台:

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

注意我们如何使用索引访问数组单元格。方括号之间的数字是我们要访问的数组的特定位置。

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

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

遍历数组

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

第一种方法是使用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打印到控制台。我们可以看到,我们利用了长度属性。这是一个公共属性,它给出了数组的大小。

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

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

这个示例与前一个示例相同,但是我们去掉了索引样板代码。foreach循环是一个选项,当:

  • 我们不需要修改数组(在元素中放入另一个值不会修改数组中的元素)
  • 我们不需要指标来做别的

可变参数

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

void varargsMethod(String... varargs) {}

这个方法可以从0到任意数量的字符串参数。一篇关于varargs的文章可以在这里找到。

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

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

将表现为:

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

数组转换为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);

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

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

数组转Stream

现在我们可以将数组转换为列表,但是由于Java 8允许访问流API,所以我们可能希望将数组转换为流。Java为我们提供了Arrays.stream方法:

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

当将一个对象数组传递给方法时,它将返回一个匹配类型的流(例如,一个整数数组的流Stream<Integer>)。当传递一个基元流时,它将返回相应的基元流。

也可以只在数组的一个子集上创建流:

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

这将创建一个Stream<Integer>,只有“Tomato”和“Chips”字符串(第一个索引包含所有索引,而第二个索引是独占索引)。

排序

现在让我们来看看如何排序一个数组,它按照一定的顺序重新排列它的元素。Arrays类为我们提供了sort方法。有点像stream方法,sort有很多重载。

  • 基本类型数组:按升序排列
  • 对象数组(这些对象必须实现Comparable接口):按照自然顺序排序(依赖于Comparable中的compareTo方法)
  • 泛型数组:根据给定的比较器进行排序

此外,可以只对数组的特定部分排序(将start和end索引传递给方法)。

排序方法背后的算法分别是对基本数组和其他数组进行快速排序和归并排序。

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"}

数组搜索

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

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为我们提供了数组。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。注意,我们使用了一个已经排序的数组。

连接数组

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

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]);
}

可以看到,当索引仍然小于第一个数组长度时,我们从该数组中添加元素。然后我们从第二个元素中添加元素。我们可以利用数组。避免编写循环的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。该方法采用源数组、源位置、目标数组、目标位置和定义要复制的元素数量的int值:

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

可以看到,复制第一个数组,然后复制第二个数组(在第一个数组的最后一个元素之后)。

总结

在这篇详细的文章中,我们介绍了Java中数组的基本用法和一些高级用法。

我们看到Java通过arrays实用程序类提供了许多处理数组的方法。还有一些实用程序类可以在Apache CommonsGuava等库中操作数组。

【腾讯云】境外1核2G服务器低至2折,半价续费券限量免费领取!
https://cloud.tencent.com/act/cps/redirect?redirect=1068&cps_key=e4b50f6c64a4480367f8a8d16fd07c5a&from=console

标签: java, List, Streams

添加新评论