{% raw %}
Java 数组
原文:http://zetcode.com/lang/java/arrays/
在 Java 教程的这一部分中,我们将介绍数组。 数组是一个包含固定数量的单一类型值的容器对象。 创建数组时将确定数组的长度。 创建后,其长度是固定的。
标量变量一次只能容纳一项。 数组可以容纳多个项目。 这些项目称为数组的元素。 数组存储相同数据类型的数据。 每个元素都可以由索引引用。 数组从零开始。 第一个元素的索引为零。
Java 数组定义
数组用于存储我们应用的数据。 我们声明数组为某种数据类型。 我们指定它们的长度。 我们用数据初始化数组。 我们有几种使用数组的方法。 我们可以修改元素,对其进行排序,复制或搜索。
int[] ages;
String[] names;
float[] weights;
我们有三个数组声明。 该声明包括两部分:数组的类型和数组的名称。 数组的类型具有确定数组中元素的类型(在我们的情况下为int
,String
和float
)的数据类型,并带有一对方括号[]
。 方括号表示我们有一个数组。
集合具有类似数组的作用。 它们比数组更强大。 稍后将在单独的章节中进行介绍。
Java 初始化数组
有几种方法可以用 Java 初始化数组。 在第一个示例中,分两个步骤创建和初始化一个数组。
com/zetcode/InitArray.java
package com.zetcode;
import java.util.Arrays;
public class InitArray {
public static void main(String[] args) {
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 InitArray.java
[1, 2, 3, 4, 5]
这是com.zetcode.InitArray
示例的输出。
我们可以在一个语句中声明并初始化一个数组。
com/zetcode/InitArray2.java
package com.zetcode;
import java.util.Arrays;
public class InitArray2 {
public static void main(String[] args) {
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 };
一步创建并初始化一个数组。 元素在大括号中指定。 我们没有指定数组的长度。 编译器将为我们完成此任务。
通过仅指定大括号之间的数字,可以进一步简化一步创建和初始化。
com/zetcode/InitArray3.java
package com.zetcode;
import java.util.Arrays;
public class InitArray3 {
public static void main(String[] args) {
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
关键字,该数组的创建方式也与前两个示例相同。 这只是一个方便的速记符号。
Java 数组访问元素
创建数组后,可以通过其索引访问其元素。 索引是放在数组名称后面方括号内的数字。
com/zetcode/AccessingElements.java
package com.zetcode;
public class AccessingElements {
public static void main(String[] args) {
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]
构造中,我们引用了名称数组的第一个元素。
$ java AccessingElements.java
Jane
Thomas
Lucy
David
运行示例,我们得到上面的输出。
可以更改数组的元素。 元素不是一成不变的。
com/zetcode/AccessingElements2.java
package com.zetcode;
import java.util.Arrays;
public class AccessingElements2 {
public static void main(String[] args) {
int[] vals = { 1, 2, 3 };
vals[0] *= 2;
vals[1] *= 2;
vals[2] *= 2;
System.out.println(Arrays.toString(vals));
}
}
我们有一个由三个整数组成的数组。 每个值都将乘以 2。
int[] vals = { 1, 2, 3 };
创建一个由三个整数组成的数组。
vals[0] *= 2;
vals[1] *= 2;
vals[2] *= 2;
使用元素访问,我们将数组中的每个值乘以 2。
$ java AccessingElements2.java
[2, 4, 6]
所有三个整数均已乘以数字 2。
Java 遍历数组
我们经常需要遍历数组的所有元素。 我们展示了两种遍历数组的常用方法。
com/zetcode/TraversingArrays.java
package com.zetcode;
public class TraversingArrays {
public static void main(String[] args) {
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
关键字使代码更紧凑。 在每个循环中,将行星变量传递给行星数组中的下一个值。
Java 将数组传递给方法
在下一个示例中,我们将数组传递给方法。
com/zetcode/PassingArrays.java
package com.zetcode;
import java.util.Arrays;
public class PassingArray {
public static void main(String[] args) {
int[] a = { 3, 4, 5, 6, 7 };
int[] r = reverseArray(a);
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(r));
}
private static 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()
方法。
private static 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 PassingArray.java
[3, 4, 5, 6, 7]
[7, 6, 5, 4, 3]
这是示例的输出。
Java 多维数组
到目前为止,我们一直在处理一维数组。 在 Java 中,我们可以创建多维数组。 多维数组是数组的数组。 在这样的数组中,元素本身就是数组。 在多维数组中,我们使用两组或更多组括号。
com/zetcode/TwoDimensions.java
package com.zetcode;
public class TwoDimensions {
public static void main(String[] args) {
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 TwoDimensions.java
1
2
3
1
2
3
这是程序的输出。
以类似的方式,我们创建了一个三维整数数组。
com/zetcode/ThreeDimensions.java
package com.zetcode;
public class ThreeDimensions {
public static void main(String[] args) {
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] + " ");
}
}
}
System.out.print('\n');
}
}
拥有三维数组的变量用三对方括号声明。 这些值放在三对大括号内。
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 ThreeDimensions.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
我们将三维数组的内容打印到控制台。
Java 不规则数组
元素大小相同的数组称为矩形数组。 可以创建数组大小不同的不规则数组。 在 C# 中,此类数组称为锯齿状数组。
com/zetcode/IrregularArrays.java
package com.zetcode;
public class IrregularArrays {
public static void main(String[] args) {
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 + " ");
}
}
System.out.print('\n');
}
}
这是不规则数组的示例。
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 IrregularArrays.java
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
package com.zetcode;
import java.util.Arrays;
public class ArrayMethods {
public static void main(String[] args) {
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 ArrayMethods.java
[1, 2, 3, 4, 5]
[8, 8, 8, 8, 8]
Arrays a, b are equal
这是输出。
Java 比较数组
比较数组有两种方法。 equals()
方法和deepEquals()
方法。 deepEquals()
方法也将引用与数组内部的数组进行比较。
com/zetcode/ComparingArrays.java
package com.zetcode;
import java.util.Arrays;
public class ComparingArrays {
public static void main(String[] args) {
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
数组有两个内部数组。 内部数组的元素等于a
和b
数组。
int[][] d = {
a,
b
};
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");
}
现在,使用这两种方法比较c
和d
数组。 对于equals()
方法,数组不相等。 deepEquals()
方法在引用数组中更深入,并检索它们的元素以进行比较。 对于此方法,c
和d
数组相等。
$ java ComparingArrays.java
equals() method: Arrays c, d are not equal
deepEquals() method: Arrays c, d are equal
这是示例输出。
Java 搜索数组
Arrays
类具有一种用于搜索数组中元素的简单方法。 它称为binarySearch()
。 该方法使用二进制搜索算法搜索元素。 binarySearch()
方法仅适用于排序数组。
com/zetcode/Searching.java
package com.zetcode;
import java.util.Arrays;
public class Searching {
public static void main(String[] args) {
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 = String.format("%s was found at position %d of the "
+ "sorted array", p, r);
} else {
msg = 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 = String.format("%s was found at position %d of the "
+ "sorted array", p, r);
} else {
msg = p + " was not found";
}
根据返回的值,我们创建一条消息。
$ java Searching.java
Earth was found at position 0 of the sorted array
This is the example output.
下载图片
在下一个示例中,我们显示如何下载图像。
com/zetcode/DownloadImage.java
package com.zetcode;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
public class DownloadImage {
public static void main(String[] args) throws IOException {
var imageUrl = "http://webcode.me/favicon.ico";
var destinationFile = "favicon.ico";
var url = new URL(imageUrl);
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 教程的这一部分中,我们使用了数组。 我们已经描述了如何初始化数组,访问数组元素,遍历数组,使用多维数组,比较数组以及搜索数组元素。
{% endraw %}