ZetCode

Java 数组

上次修改时间:2024 年 2 月 23 日

在本文中,我们将介绍数组。数组是一个容器对象,它保存固定数量的单一类型的值。数组的长度在创建时确定。创建后,其长度是固定的。

标量变量一次只能保存一个项目。数组可以保存多个项目。这些项目被称为数组的元素。数组存储相同数据类型的数据。每个元素都可以通过索引来引用。数组从零开始。第一个元素的索引是零。

数组定义

数组用于存储应用程序的数据。我们声明数组为某种数据类型,指定它们的长度,并使用数据初始化数组。我们有几种方法可以处理数组。我们可以修改元素、对其排序、复制它们或搜索它们。

int[] ages;
String[] names;
float[] weights;

我们有三个数组声明。声明由两部分组成:数组的类型和数组的名称。数组的类型具有一个数据类型,该数据类型确定数组中元素的类型(在我们的例子中是intStringfloat)以及一对中括号[]。中括号表示我们有一个数组。

集合 的作用与数组类似。它们比数组更强大。我们将在后面的章节中单独介绍它们。

初始化数组

在 Java 中,我们可以使用多种方法来初始化数组。在第一个例子中,数组分两步创建和初始化。

Main.java
import java.util.Arrays;

void main() {

    int[] a = new int[5];

    a[0] = 1;
    a[1] = 2;
    a[2] = 3;
    a[3] = 4;
    a[4] = 5;

    System.out.println(Arrays.toString(a));
}

我们创建并初始化一个数字数组。数组的内容会打印到控制台。

int[] a = new int[5];

这里我们创建一个可以包含五个元素的数组。该语句为五个整数分配内存。中括号用于声明数组,类型(在我们的例子中是 int)告诉我们数组将保存什么类型的值。数组是一个对象,因此它使用 new 关键字创建。

a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;

我们用一些数据初始化数组。这是赋值初始化。索引在中括号中。数字 1 将成为数组的第一个元素,数字 2 是第二个元素,依此类推。

System.out.println(Arrays.toString(a));

Arrays 类是一个助手类,它包含用于操作数组的各种方法。toString 方法返回指定数组内容的字符串表示形式。此方法有助于调试。

$ java Main.java
[1, 2, 3, 4, 5]

我们可以在一条语句中声明和初始化数组。

Main.java
import java.util.Arrays;

void main() {

    int[] a = new int[] { 2, 4, 5, 6, 7, 3, 2 };

    System.out.println(Arrays.toString(a));
}

这是上一个程序的修改版本。

int[] array = new int[] { 2, 4, 5, 6, 7, 3, 2 };

数组一步创建和初始化。元素在花括号中指定。我们没有指定数组的长度。编译器会为我们完成。

通过仅指定花括号之间的数字,可以进一步简化一步创建和初始化。

Main.java
import java.util.Arrays;

void main() {

    int[] a = { 2, 4, 5, 6, 7, 3, 2 };

    System.out.println(Arrays.toString(a));
}

使用最简单的数组创建方法创建整数数组。

int[] a = { 2, 4, 5, 6, 7, 3, 2 };

可以省略 new int[] 构造。该语句的右侧是数组字面量表示法。它类似于 C/C++ 风格的数组初始化。即使我们删除 new 关键字,数组的创建方式也与前两个示例相同。这只是一个方便的简写表示法。

访问数组元素

创建数组后,可以通过索引访问其元素。索引是一个数字,位于数组名称后面的方括号内。

Main.java
void main() {

    String[] names = {"Jane", "Thomas", "Lucy", "David"};

    System.out.println(names[0]);
    System.out.println(names[1]);
    System.out.println(names[2]);
    System.out.println(names[3]);
}

在此示例中,我们创建一个字符串名称数组。我们通过索引访问每个元素并将其打印到终端。

String[] names = {"Jane", "Thomas", "Lucy", "David"};

创建字符串数组。

System.out.println(names[0]);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);

数组的每个元素都打印到控制台。使用 names[0] 构造,我们引用 names 数组的第一个元素。

$ java Main.java
Jane
Thomas
Lucy
David

运行该示例,我们得到以上输出。

可以更改数组的元素。元素不是不可变的。

Main.java
import java.util.Arrays;

void main() {

    int[] vals = { 1, 2, 3 };

    vals[0] *= 2;
    vals[1] *= 2;
    vals[2] *= 2;

    System.out.println(Arrays.toString(vals));
}

我们有一个包含三个整数的数组。每个值都将乘以二。

int[] vals = { 1, 2, 3 };

创建一个包含三个整数的数组。

vals[0] *= 2;
vals[1] *= 2;
vals[2] *= 2;

使用元素访问,我们将数组中的每个值乘以二。

$ java Main.java
[2, 4, 6]

遍历数组

我们经常需要遍历数组的所有元素。我们展示了两种常用的遍历数组的方法。

Main.java
void main() {

    String[] planets = { "Mercury", "Venus", "Mars", "Earth", "Jupiter",
            "Saturn", "Uranus", "Neptune", "Pluto" };

    for (int i = 0; i < planets.length; i++) {

        System.out.println(planets[i]);
    }

    for (String planet : planets) {

        System.out.println(planet);
    }
}

创建行星名称数组。我们使用 for 循环来打印所有值。

for (int i=0; i < planets.length; i++) {

    System.out.println(planets[i]);
}

在此循环中,我们利用了可以从数组对象中获取元素数量的事实。元素的数量存储在 length 常量中。

for (String planet : planets) {

    System.out.println(planet);
}

可以使用增强的 for 关键字在遍历数组或其他集合时使代码更紧凑。在每个循环中,行星变量都会从行星数组中传递下一个值。

将数组传递给方法

在下一个示例中,我们将数组传递给方法。

Main.java
import java.util.Arrays;

void main() {

    int[] a = { 3, 4, 5, 6, 7 };
    int[] r = reverseArray(a);

    System.out.println(Arrays.toString(a));
    System.out.println(Arrays.toString(r));
}

int[] reverseArray(int[] b) {

    int[] c = new int[b.length];

    for (int i = b.length - 1, j = 0; i >= 0; i--, j++) {

        c[j] = b[i];
    }

    return c;
}

该示例对数组的元素重新排序。为此,创建了一个 reverseArray 方法。

int[] reverseArray(int[] b) {

reverseArray 方法接受一个数组作为参数并返回一个数组。该方法获取传递的数组的副本。

int[] c = new int[b.length];

在该方法的主体内部,创建一个新数组;它将包含新排序的元素。

for (int i = b.length - 1, j = 0; i >= 0; i--, j++) {

    c[j] = b[i];
}

在此 for 循环中,我们使用复制的数组的元素填充新数组。元素被反转。

return c;

新形成的数组返回给调用者。

System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(r));

我们打印原始数组和反转数组的元素。

$ java Main.java
[3, 4, 5, 6, 7]
[7, 6, 5, 4, 3]

多维数组

到目前为止,我们一直在使用一维数组。在 Java 中,我们可以创建多维数组。多维数组是数组的数组。在这种数组中,元素本身就是数组。在多维数组中,我们使用两组或多组括号。

Main.java
void main() {

    int[][] twodim = new int[][] { { 1, 2, 3 }, { 1, 2, 3 } };

    int d1 = twodim.length;
    int d2 = twodim[1].length;

    for (int i = 0; i < d1; i++) {

        for (int j = 0; j < d2; j++) {

            System.out.println(twodim[i][j]);
        }
    }
}

在此示例中,我们创建一个二维整数数组。

int[][] twodim = new int[][] { { 1, 2, 3 }, { 1, 2, 3 } };

使用两对方括号来声明二维数组。在花括号内,我们还有另外两对花括号。它们表示两个内部数组。

int d1 = twodim.length;
int d2 = twodim[1].length;

我们确定容纳其他两个数组的外部数组和第二个内部数组的长度。

for (int i = 0; i < d1; i++) {

    for (int j = 0; j < d2; j++) {

        System.out.println(twodim[i][j]);
    }
}

两个 for 循环用于打印二维数组中的所有六个值。twodim[i][j] 数组的第一个索引是指其中一个内部数组。第二个索引是指所选内部数组的元素。

$ java Main.java
1
2
3
1
2
3

以类似的方式,我们创建一个三维整数数组。

Main.java
void main() {

    int[][][] n3 = {
            { { 12, 2, 8 }, { 0, 2, 1 } },
            { { 14, 5, 2 }, { 0, 5, 4 } },
            { { 3, 26, 9 }, { 8, 7, 1 } },
            { { 4, 11, 2 }, { 0, 9, 6 } }
    };

    int d1 = n3.length;
    int d2 = n3[0].length;
    int d3 = n3[0][0].length;

    for (int i = 0; i < d1; i++) {

        for (int j = 0; j < d2; j++) {

            for (int k = 0; k < d3; k++) {

                System.out.print(n3[i][j][k] + " ");
            }
        }
    }
}

声明一个保存三维数组的变量时,需要使用三对方括号。这些值放置在三对花括号中。

int[][][] n3 = {
    { { 12, 2, 8 }, { 0, 2, 1 } },
    { { 14, 5, 2 }, { 0, 5, 4 } },
    { { 3, 26, 9 }, { 8, 7, 1 } },
    { { 4, 11, 2 }, { 0, 9, 6 } }
};

创建三维数组 n3。它是一个数组,其元素本身就是数组的数组。

int d1 = n3.length;
int d2 = n3[0].length;
int d3 = n3[0][0].length;

我们获取所有三个维度的长度。

for (int i = 0; i < d1; i++) {

    for (int j = 0; j < d2; j++) {

        for (int k = 0; k < d3; k++) {

            System.out.print(n3[i][j][k] + " ");
        }
    }
}

我们需要三个 for 循环来遍历三维数组。

$ java Main.java
12 2 8 0 2 1 14 5 2 0 5 4 3 26 9 8 7 1 4 11 2 0 9 6

不规则数组

具有相同大小元素的数组称为矩形数组。可以创建不规则的数组,其中数组的大小不同。在 C# 中,此类数组称为交错数组

Main.java
void main() {

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

    for (int[] a : ir) {
        for (int e : a) {
            System.out.print(e + " ");
        }
    }
}

这是一个不规则数组的示例。

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

这是不规则数组的声明和初始化。三个内部数组分别具有 2、3 和 4 个元素。

for (int[] a : ir) {
    for (int e : a) {
        System.out.print(e + " ");
    }
}

增强的 for 循环用于遍历数组的所有元素。

$ java Main.java
1 2 1 2 3 1 2 3 4

数组方法

Arrays 类(可在 java.util 包中使用)是一个帮助类,其中包含用于处理数组的方法。这些方法可用于修改、排序、复制或搜索数据。我们使用的这些方法是 Array 类的静态方法。(静态方法是可以调用而无需创建类实例的方法。)

Main.java
import java.util.Arrays;

void main() {

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

    Arrays.sort(a);

    System.out.println(Arrays.toString(a));

    Arrays.fill(a, 8);
    System.out.println(Arrays.toString(a));

    int[] b = Arrays.copyOf(a, 5);

    if (Arrays.equals(a, b)) {

        System.out.println("Arrays a, b are equal");
    } else {

        System.out.println("Arrays a, b are not equal");
    }
}

在代码示例中,我们介绍了 Arrays 类的五种方法。

import java.util.Arrays;

我们将使用 Arrays 类的简写表示法。

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

我们有一个包含五个整数的数组。

Arrays.sort(a);

sort 方法按升序对整数进行排序。

System.out.println(Arrays.toString(a));

toString 方法返回指定数组内容的字符串表示形式。

Arrays.fill(a, 8);

fill 方法将指定的整数值分配给数组的每个元素。

int[] b = Arrays.copyOf(a, 5);

copyOf 方法将指定数量的元素复制到新数组。

if (Arrays.equals(a, b)) {

    System.out.println("Arrays a, b are equal");
} else {

    System.out.println("Arrays a, b are not equal");
}

equals 方法比较两个数组。如果两个数组包含相同的元素且顺序相同,则它们相等。

$ java Main.java
[1, 2, 3, 4, 5]
[8, 8, 8, 8, 8]
Arrays a, b are equal

比较数组

有两种比较数组的方法。equals 方法和 deepEquals 方法。deepEquals 方法还会比较数组内部数组的引用。

Main.java
import java.util.Arrays;

void main() {

    int[] a = { 1, 1, 2, 1, 1 };
    int[] b = { 0, 0, 3, 0, 0 };

    int[][] c = {
            { 1, 1, 2, 1, 1 },
            { 0, 0, 3, 0, 0 }
    };

    int[][] d = {
            a,
            b
    };

    System.out.print("equals() method: ");

    if (Arrays.equals(c, d)) {

        System.out.println("Arrays c, d are equal");
    } else {

        System.out.println("Arrays c, d are not equal");
    }

    System.out.print("deepEquals() method: ");

    if (Arrays.deepEquals(c, d)) {

        System.out.println("Arrays c, d are equal");
    } else {

        System.out.println("Arrays c, d are not equal");
    }
}

该示例解释了这两种方法之间的区别。

int[] a = { 1, 1, 2, 1, 1 };
int[] b = { 0, 0, 3, 0, 0 };

我们有两个整数数组。

int[][] c = {
    { 1, 1, 2, 1, 1 },
    { 0, 0, 3, 0, 0 }
};

c 数组有两个内部数组。内部数组的元素等于 ab 数组。

int[][] d = {
    a,
    b
};

d 数组包含对 ab 数组的引用。

System.out.print("equals() method: ");

if (Arrays.equals(c, d)) {

    System.out.println("Arrays c, d are equal");
} else {

    System.out.println("Arrays c, d are not equal");
}

System.out.print("deepEquals() method: ");

if (Arrays.deepEquals(c, d)) {

    System.out.println("Arrays c, d are equal");
} else {

    System.out.println("Arrays c, d are not equal");
}

现在,使用两种方法比较 cd 数组。对于 equals 方法,数组不相等。deepEquals 方法会更深入地访问引用的数组,并检索其元素以进行比较。对于此方法,cd 数组是相等的。

$ java Main.java
equals() method: Arrays c, d are not equal
deepEquals() method: Arrays c, d are equal

搜索数组

Arrays 类有一个简单的方法来搜索数组中的元素。它被称为 binarySearch。该方法使用二分搜索算法搜索元素。binarySearch 方法仅适用于排序后的数组。

Main.java
import java.util.Arrays;

void main() {

    String[] planets = { "Mercury", "Venus", "Mars", "Earth", "Jupiter",
            "Saturn", "Uranus", "Neptune", "Pluto" };

    Arrays.sort(planets);

    String p = "Earth";
    int r = Arrays.binarySearch(planets, p);

    String msg = "";

    if (r >= 0) {
        msg = STR."\{p} was found at position \{r} of the sorted array";
    } else {
        msg = STR."\{p} was not found";
    }

    System.out.println(msg);
}

在此示例中,我们在行星数组中搜索“Earth”字符串。

Arrays.sort(planets);

由于该算法仅适用于排序后的数组,因此我们必须首先对数组进行排序。

String p = "Earth";

我们将搜索“Earth”元素。

int r = Arrays.binarySearch(planets, p);

调用 binarySearch 方法。第一个参数是数组名称,第二个参数是我们正在寻找的元素。如果找到该元素,则返回值大于或等于零。在这种情况下,它是该元素在排序数组中的索引。

if (r >= 0) {
    msg = STR."\{p} was found at position \{r} of the sorted array";
} else {
    msg = STR."\{p} was not found";
}

根据返回的值,我们创建一个消息。

$ java Main.java
Earth was found at position 0 of the sorted array

下载图片

在下一个示例中,我们将展示如何下载图像。

Main.java
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

void main() throws IOException, URISyntaxException {

    String imageUrl = "https://something.com/favicon.ico";
    String destinationFile = "favicon.ico";

    var url = new URI(imageUrl).toURL();

    try (var is = url.openStream();
            var fos = new FileOutputStream(destinationFile)) {

        byte[] buf = new byte[1024];
        int noOfBytes;

        while ((noOfBytes = is.read(buf)) != -1) {

            fos.write(buf, 0, noOfBytes);
        }
    }
}

该示例下载一个小的 favicon.ico 图像。

byte[] buf = new byte[1024];

图像是字节数组。我们创建一个足够大的 byte 值空数组来容纳该图标。

while ((noOfBytes = is.read(buf)) != -1) {

    fos.write(buf, 0, noOfBytes);
}

我们读取二进制数据并将其写入文件。

来源

Java 数组 - 教程

在本文中,我们使用了数组。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有Java教程