{% raw %}

Java 数组

原文:http://zetcode.com/lang/java/arrays/

在 Java 教程的这一部分中,我们将介绍数组。 数组是一个包含固定数量的单一类型值的容器对象。 创建数组时将确定数组的长度。 创建后,其长度是固定的。

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

Java 数组定义

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

  1. int[] ages;
  2. String[] names;
  3. float[] weights;

我们有三个数组声明。 该声明包括两部分:数组的类型和数组的名称。 数组的类型具有确定数组中元素的类型(在我们的情况下为intStringfloat)的数据类型,并带有一对方括号[]。 方括号表示我们有一个数组。

集合具有类似数组的作用。 它们比数组更强大。 稍后将在单独的章节中进行介绍。

Java 初始化数组

有几种方法可以用 Java 初始化数组。 在第一个示例中,分两个步骤创建和初始化一个数组。

com/zetcode/InitArray.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. public class InitArray {
  4. public static void main(String[] args) {
  5. int[] a = new int[5];
  6. a[0] = 1;
  7. a[1] = 2;
  8. a[2] = 3;
  9. a[3] = 4;
  10. a[4] = 5;
  11. System.out.println(Arrays.toString(a));
  12. }
  13. }

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

  1. int[] a = new int[5];

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

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

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

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

Arrays类是一个帮助器类,其中包含用于操纵数组的各种方法。 toString()方法返回指定数组内容的字符串表示形式。 此方法有助于调试。

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

这是com.zetcode.InitArray示例的输出。

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

com/zetcode/InitArray2.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. public class InitArray2 {
  4. public static void main(String[] args) {
  5. int[] a = new int[] { 2, 4, 5, 6, 7, 3, 2 };
  6. System.out.println(Arrays.toString(a));
  7. }
  8. }

这是先前程序的修改版本。

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

一步创建并初始化一个数组。 元素在大括号中指定。 我们没有指定数组的长度。 编译器将为我们完成此任务。

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

com/zetcode/InitArray3.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. public class InitArray3 {
  4. public static void main(String[] args) {
  5. int[] a = { 2, 4, 5, 6, 7, 3, 2 };
  6. System.out.println(Arrays.toString(a));
  7. }
  8. }

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

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

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

Java 数组访问元素

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

com/zetcode/AccessingElements.java

  1. package com.zetcode;
  2. public class AccessingElements {
  3. public static void main(String[] args) {
  4. String[] names = {"Jane", "Thomas", "Lucy", "David"};
  5. System.out.println(names[0]);
  6. System.out.println(names[1]);
  7. System.out.println(names[2]);
  8. System.out.println(names[3]);
  9. }
  10. }

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

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

将创建一个字符串数组。

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

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

  1. $ java AccessingElements.java
  2. Jane
  3. Thomas
  4. Lucy
  5. David

运行示例,我们得到上面的输出。

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

com/zetcode/AccessingElements2.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. public class AccessingElements2 {
  4. public static void main(String[] args) {
  5. int[] vals = { 1, 2, 3 };
  6. vals[0] *= 2;
  7. vals[1] *= 2;
  8. vals[2] *= 2;
  9. System.out.println(Arrays.toString(vals));
  10. }
  11. }

我们有一个由三个整数组成的数组。 每个值都将乘以 2。

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

创建一个由三个整数组成的数组。

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

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

  1. $ java AccessingElements2.java
  2. [2, 4, 6]

所有三个整数均已乘以数字 2。

Java 遍历数组

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

com/zetcode/TraversingArrays.java

  1. package com.zetcode;
  2. public class TraversingArrays {
  3. public static void main(String[] args) {
  4. String[] planets = { "Mercury", "Venus", "Mars", "Earth", "Jupiter",
  5. "Saturn", "Uranus", "Neptune", "Pluto" };
  6. for (int i=0; i < planets.length; i++) {
  7. System.out.println(planets[i]);
  8. }
  9. for (String planet : planets) {
  10. System.out.println(planet);
  11. }
  12. }
  13. }

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

  1. for (int i=0; i < planets.length; i++) {
  2. System.out.println(planets[i]);
  3. }

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

  1. for (String planet : planets) {
  2. System.out.println(planet);
  3. }

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

Java 将数组传递给方法

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

com/zetcode/PassingArrays.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. public class PassingArray {
  4. public static void main(String[] args) {
  5. int[] a = { 3, 4, 5, 6, 7 };
  6. int[] r = reverseArray(a);
  7. System.out.println(Arrays.toString(a));
  8. System.out.println(Arrays.toString(r));
  9. }
  10. private static int[] reverseArray(int[] b) {
  11. int[] c = new int[b.length];
  12. for (int i=b.length-1, j=0; i>=0; i--, j++) {
  13. c[j] = b[i];
  14. }
  15. return c;
  16. }
  17. }

该示例重新排列数组的元素。 为此,创建了reverseArray()方法。

  1. private static int[] reverseArray(int[] b) {

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

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

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

  1. for (int i=b.length-1, j=0; i>=0; i--, j++) {
  2. c[j] = b[i];
  3. }

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

  1. return c;

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

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

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

  1. $ java PassingArray.java
  2. [3, 4, 5, 6, 7]
  3. [7, 6, 5, 4, 3]

这是示例的输出。

Java 多维数组

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

com/zetcode/TwoDimensions.java

  1. package com.zetcode;
  2. public class TwoDimensions {
  3. public static void main(String[] args) {
  4. int[][] twodim = new int[][] { {1, 2, 3}, {1, 2, 3} };
  5. int d1 = twodim.length;
  6. int d2 = twodim[1].length;
  7. for (int i = 0; i < d1; i++) {
  8. for (int j = 0; j < d2; j++) {
  9. System.out.println(twodim[i][j]);
  10. }
  11. }
  12. }
  13. }

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

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

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

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

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

  1. for (int i = 0; i < d1; i++) {
  2. for (int j = 0; j < d2; j++) {
  3. System.out.println(twodim[i][j]);
  4. }
  5. }

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

  1. $ java TwoDimensions.java
  2. 1
  3. 2
  4. 3
  5. 1
  6. 2
  7. 3

这是程序的输出。

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

com/zetcode/ThreeDimensions.java

  1. package com.zetcode;
  2. public class ThreeDimensions {
  3. public static void main(String[] args) {
  4. int[][][] n3 = {
  5. {{12, 2, 8}, {0, 2, 1}},
  6. {{14, 5, 2}, {0, 5, 4}},
  7. {{3, 26, 9}, {8, 7, 1}},
  8. {{4, 11, 2}, {0, 9, 6}}
  9. };
  10. int d1 = n3.length;
  11. int d2 = n3[0].length;
  12. int d3 = n3[0][0].length;
  13. for (int i = 0; i < d1; i++) {
  14. for (int j = 0; j < d2; j++) {
  15. for (int k = 0; k < d3; k++) {
  16. System.out.print(n3[i][j][k] + " ");
  17. }
  18. }
  19. }
  20. System.out.print('\n');
  21. }
  22. }

拥有三维数组的变量用三对方括号声明。 这些值放在三对大括号内。

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

创建三维数组n3。 它是一个具有元素的数组,这些元素本身就是数组的数组。

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

我们得到所有三个维度的长度。

  1. for (int i = 0; i < d1; i++) {
  2. for (int j = 0; j < d2; j++) {
  3. for (int k = 0; k < d3; k++) {
  4. System.out.print(n3[i][j][k] + " ");
  5. }
  6. }
  7. }

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

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

我们将三维数组的内容打印到控制台。

Java 不规则数组

元素大小相同的数组称为矩形数组。 可以创建数组大小不同的不规则数组。 在 C# 中,此类数组称为锯齿状数组。

com/zetcode/IrregularArrays.java

  1. package com.zetcode;
  2. public class IrregularArrays {
  3. public static void main(String[] args) {
  4. int[][] ir = new int[][] {
  5. {1, 2},
  6. {1, 2, 3},
  7. {1, 2, 3, 4}
  8. };
  9. for (int[] a : ir) {
  10. for (int e : a) {
  11. System.out.print(e + " ");
  12. }
  13. }
  14. System.out.print('\n');
  15. }
  16. }

这是不规则数组的示例。

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

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

  1. for (int[] a : ir) {
  2. for (int e : a) {
  3. System.out.print(e + " ");
  4. }
  5. }

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

  1. $ java IrregularArrays.java
  2. 1 2 1 2 3 1 2 3 4

This is the output of the example.

Java 数组方法

java.util包中提供的Arrays类是一个帮助器类,其中包含使用数组的方法。 这些方法可用于修改,排序,复制或搜索数据。 我们使用的这些方法是Array类的静态方法。 (静态方法是可以在不创建类实例的情况下调用的方法。)

com/zetcode/ArrayMethods.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. public class ArrayMethods {
  4. public static void main(String[] args) {
  5. int[] a = {5, 2, 4, 3, 1};
  6. Arrays.sort(a);
  7. System.out.println(Arrays.toString(a));
  8. Arrays.fill(a, 8);
  9. System.out.println(Arrays.toString(a));
  10. int[] b = Arrays.copyOf(a, 5);
  11. if (Arrays.equals(a, b)) {
  12. System.out.println("Arrays a, b are equal");
  13. } else {
  14. System.out.println("Arrays a, b are not equal");
  15. }
  16. }
  17. }

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

  1. import java.util.Arrays;

我们将对Arrays类使用简写形式。

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

我们有五个整数的数组。

  1. Arrays.sort(a);

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

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

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

  1. Arrays.fill(a, 8);

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

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

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

  1. if (Arrays.equals(a, b)) {
  2. System.out.println("Arrays a, b are equal");
  3. } else {
  4. System.out.println("Arrays a, b are not equal");
  5. }

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

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

这是输出。

Java 比较数组

比较数组有两种方法。 equals()方法和deepEquals()方法。 deepEquals()方法也将引用与数组内部的数组进行比较。

com/zetcode/ComparingArrays.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. public class ComparingArrays {
  4. public static void main(String[] args) {
  5. int[] a = {1, 1, 2, 1, 1};
  6. int[] b = {0, 0, 3, 0, 0};
  7. int[][] c = {
  8. {1, 1, 2, 1, 1},
  9. {0, 0, 3, 0, 0}
  10. };
  11. int[][] d = {
  12. a,
  13. b
  14. };
  15. System.out.print("equals() method: ");
  16. if (Arrays.equals(c, d)) {
  17. System.out.println("Arrays c, d are equal");
  18. } else {
  19. System.out.println("Arrays c, d are not equal");
  20. }
  21. System.out.print("deepEquals() method: ");
  22. if (Arrays.deepEquals(c, d)) {
  23. System.out.println("Arrays c, d are equal");
  24. } else {
  25. System.out.println("Arrays c, d are not equal");
  26. }
  27. }
  28. }

该示例说明了两种方法之间的区别。

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

我们有两个整数数组。

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

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

  1. int[][] d = {
  2. a,
  3. b
  4. };

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

  1. System.out.print("equals() method: ");
  2. if (Arrays.equals(c, d)) {
  3. System.out.println("Arrays c, d are equal");
  4. } else {
  5. System.out.println("Arrays c, d are not equal");
  6. }
  7. System.out.print("deepEquals() method: ");
  8. if (Arrays.deepEquals(c, d)) {
  9. System.out.println("Arrays c, d are equal");
  10. } else {
  11. System.out.println("Arrays c, d are not equal");
  12. }

现在,使用这两种方法比较cd数组。 对于equals()方法,数组不相等。 deepEquals()方法在引用数组中更深入,并检索它们的元素以进行比较。 对于此方法,cd数组相等。

  1. $ java ComparingArrays.java
  2. equals() method: Arrays c, d are not equal
  3. deepEquals() method: Arrays c, d are equal

这是示例输出。

Java 搜索数组

Arrays类具有一种用于搜索数组中元素的简单方法。 它称为binarySearch()。 该方法使用二进制搜索算法搜索元素。 binarySearch()方法仅适用于排序数组。

com/zetcode/Searching.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. public class Searching {
  4. public static void main(String[] args) {
  5. String[] planets = { "Mercury", "Venus", "Mars", "Earth", "Jupiter",
  6. "Saturn", "Uranus", "Neptune", "Pluto" };
  7. Arrays.sort(planets);
  8. String p = "Earth";
  9. int r = Arrays.binarySearch(planets, p);
  10. String msg;
  11. if (r >= 0) {
  12. msg = String.format("%s was found at position %d of the "
  13. + "sorted array", p, r);
  14. } else {
  15. msg = p + " was not found";
  16. }
  17. System.out.println(msg);
  18. }
  19. }

在该示例中,我们在一系列行星中搜索"Earth"字符串。

  1. Arrays.sort(planets);

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

  1. String p = "Earth";

我们将搜索"Earth"元素。

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

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

  1. if (r >= 0) {
  2. msg = String.format("%s was found at position %d of the "
  3. + "sorted array", p, r);
  4. } else {
  5. msg = p + " was not found";
  6. }

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

  1. $ java Searching.java
  2. Earth was found at position 0 of the sorted array

This is the example output.

下载图片

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

com/zetcode/DownloadImage.java

  1. package com.zetcode;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.net.URL;
  5. public class DownloadImage {
  6. public static void main(String[] args) throws IOException {
  7. var imageUrl = "http://webcode.me/favicon.ico";
  8. var destinationFile = "favicon.ico";
  9. var url = new URL(imageUrl);
  10. try (var is = url.openStream();
  11. var fos = new FileOutputStream(destinationFile)) {
  12. byte[] buf = new byte[1024];
  13. int noOfBytes;
  14. while ((noOfBytes = is.read(buf)) != -1) {
  15. fos.write(buf, 0, noOfBytes);
  16. }
  17. }
  18. }
  19. }

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

  1. byte[] buf = new byte[1024];

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

  1. while ((noOfBytes = is.read(buf)) != -1) {
  2. fos.write(buf, 0, noOfBytes);
  3. }

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

在 Java 教程的这一部分中,我们使用了数组。 我们已经描述了如何初始化数组,访问数组元素,遍历数组,使用多维数组,比较数组以及搜索数组元素。

{% endraw %}