你好!之前在您的培训中,我们使用过单个对象(和原始类型)。但是,如果我们需要处理一整组对象而不是一个对象怎么办?例如,假设我们要创建我们公司所有员工的生日列表。它应该包含 30 个字符串,格式如下:"Sarah Huffman, January 25" 我们将从称为数组的特殊数据结构中获益。如果我们将数组比作一个真实的对象,它非常类似于带有保险箱的银行金库:
数组也由“盒子”组成。你可以在每个盒子里放一些东西(一个元素)。要访问一个元素,您需要知道它的框号(索引)。这是创建数组的方式:
这意味着,如果你想在第一个盒子里放一些值,你可以这样做:
理解数组不仅仅是存储对象很重要:它本身就是一个对象。 这让我们质疑我们是否不仅可以创建字符串数组或数字数组,还可以创建数组数组。答案是肯定的,我们可以!数组可以存储任何对象,包括其他数组。这样的数组称为二维数组。如果我们用视觉来表示它,它会非常类似于一张普通的桌子。假设,我们要创建一个包含3 个数组的数组,每个数组可以存储 10
每行代表一个
在“战舰”中,比赛场地的结构可以很容易地描述:一个由 10 个数组组成的二维数组,每个数组有 10 个元素。你创建两个这样的阵列(一个给你,一个给你的对手)

public class Main {
public static void main(String[] args) {
String [] birthdays = new String[10];
}
}
这里我们创建了一个包含 10 个元素的数组。 您可以立即注意到数组的一些特征:
- 它存储定义明确的数据类型的元素。如果我们创建一个 String 数组,我们就不能在其中存储任何其他内容。数据类型是在创建数组时指定的。这是它与保险箱(客户可以在其中存放他或她想要的东西)的不同之处。
- 它的大小必须在创建数组时指定。您不能稍后指示它或在创建数组后更改其大小。
String [] birthdays = new String[10];
String birthdays [] = new String[10];
如果要将内容写入数组,则需要指定要写入值的框的索引。数组中的框从 0 开始编号。 从零开始计数是编程中非常常见的做法。你越快习惯它越好 :) 
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
}
}
现在 Jana 的生日存储在我们的员工生日数组的第一个单元格中:您可以以类似的方式添加其他值:
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
birthdays[1] = "Landon Chan, May 18";
birthdays[7] = "Rosie Mills, January 3";
}
}
请注意,我们在第八个盒子中添加了 Rosie 的生日(你不会忘记为什么 7 号盒子是第八个盒子吧?)。您可以看到我们还没有填充所有其他单元格。我们不必按顺序将值写入数组。没有这样的要求。当然,按顺序编写元素可以更容易地跟踪有多少盒子是空闲的,有多少盒子被占用,并且它可以防止数组出现“漏洞”。如果你想得到其中一个盒子里的东西,那么(就像保险箱一样)你需要知道它的号码。这是如何完成的:
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
birthdays[1] = "Landon Chan, May 18";
birthdays[7] = "Rosie Mills, January 3";
String rosieBirthday = birthdays[7];
System.out.println(rosieBirthday);
}
}
控制台输出: Rosie Mills,1 月 3 日 我们创建了一个变量并告诉编译器:“在birthdaysString
数组中找到索引为 7 的框,并将其中包含的值分配给变量rosieBirthday ”。这正是它所做的。使用数组时,我们可以使用特殊属性轻松找到它们的长度:length。 String
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
birthdays[1] = "Landon Chan, May 18";
birthdays[7] = "Rosie Mills, January 3";
int birthdaysLength = birthdays.length;
System.out.println(birthdaysLength);
}
}
控制台输出: 10 注意:该length
属性存储的是数组大小,而不是已满的框数。我们的数组只存储 3 个值,但我们在创建它时将其大小指定为 10。这正是该字段返回的值length
。为什么这会派上用场?好吧,假设您想显示所有生日的列表(以验证没有人被遗忘)。您可以在一个简单的循环中执行此操作:
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
birthdays[1] = "Landon Chan, May 18";
birthdays[2] = "Jeremiah Leonard, July 12";
birthdays [3] = "Kenny Russo, September 7";
birthdays[4] = "Tommie Barnes, November 9";
birthdays [5] = "Roman Baranov, August 14";
birthdays [6] = "Chanice Andersen, April 1";
birthdays[7] = "Rosie Mills, January 3";
birthdays [8] = "Keenan West, October 19";
birthdays [9] = "Abraham McArthur, May 3";
for (int i = 0; i < birthdays.length; i++) {
System.out.println(birthdays[i]);
}
}
}
在循环中,我们声明变量i
,它被初始化为零。每次通过时,我们都会从数组中获取索引为 i 的元素并显示其值。循环将执行 10 次迭代,并且 i 将从 0 增加到 9——数字恰好是我们数组元素的索引!因此,我们将显示从birthdays[0]到birthdays[9] 的所有值 。实际上,还有另一种创建数组的方法。例如,您可以int
像这样创建一个 s 数组:
public class Main {
public static void main(String[] args) {
int numbers [] = {7, 12, 8, 4, 33, 79, 1, 16, 2};
}
}
这种技术称为“快捷方式初始化”。这非常方便,因为我们同时创建了一个数组并用值填充它。我们不必明确指定数组大小:通过快捷方式初始化,该length
字段会自动设置。
public class Main {
public static void main(String[] args) {
int numbers [] = {7, 12, 8, 4, 33, 79, 1, 16, 2};
System.out.println(numbers.length);
}
}
控制台输出: 9 现在,稍微介绍一下数组是如何存储在内存中的。假设我们有一个包含三个Cat
对象的数组:
public class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
public static void main(String[] args) {
Cat[] cats = new Cat[3];
cats[0] = new Cat("Thomas");
cats[1] = new Cat("Behemoth");
cats[2] = new Cat("Lionel Messi");
}
}
你需要在这里了解一些事情:
-
在基元的情况下,数组存储一组特定值(例如
int
s)。对于对象,数组存储一组引用。
该cats
数组由三个元素组成,每个元素都是对一个对象的引用Cat
。每个引用都指向存储相应对象的内存地址。 - 数组元素排列在内存中的单个块中。这样做是为了能够快速有效地访问它们。
cats
引用存储所有对象(数组元素)的内存块。Cats[0]
引用此块中的特定地址。 
int
个。它看起来像这样:

int
数组。第一个数组包含从 1 到 10 的数字,第二个数组 - 从 -1 到 -10,第三个 - 一组随机数。这些数组中的每一个都存储在我们的二维数组的盒子中。在代码中,二维数组的初始化如下所示:
public static void main(String[] args) {
Cat[][] cats = new Cat[3][5];
}
我们的二维数组cats存储了3 个数组,每个数组有 5 个盒子。如果我们想把一个对象放在第二个数组的第三个盒子里,我们会这样做:
public static void main(String[] args) {
Cat[][] cats = new Cat[3][5];
cats[1][2] = new Cat("Fluffy");
}
[1]
指示第二个数组,并[2]
指示该数组的第三个框。因为二维数组由多个数组组成,为了遍历它并显示它的所有值(或填充它的所有元素),我们需要一个嵌套循环:
for (int i = 0; i < cats.length; i++) {
for (int j = 0; j < cats[i].length; j++) {
System.out.println(cats[i][j]);
}
}
在外部循环(变量i
)中,我们遍历二维数组中的所有数组。在内部循环(变量j
)中,我们遍历每个数组的所有元素。结果,cats[0][0](第一个数组,第一个元素)将首先显示,然后是cats[0][1](第一个数组,第二个元素)。在我们完成第一个数组后,我们将显示cats[1][0]、cats[1][1]、cats[1][2]等。顺便说一句,二维数组也支持速记初始化:
int[][] numbers = {{1,2,3}, {4,5,6}, {7,8,9}};
通常,我们会将二维数组声明numbers
为int[3][3]
,但这种简写让我们可以立即指定值。为什么需要二维数组?好吧,您可以使用它来轻松地重现著名的“战舰”游戏: 
int[][] battleshipBoard1 = new int[10][10];
int[][] battleshipBoard2 = new int[10][10];
使用一些值(例如数字或符号)来填充与您的船只位置相对应的元素,然后轮流调用特定元素的坐标:
- battleshipBoard1[0][2]!
- 错过!battleshipBoard2[2][4]!
- 打!
- battleshipBoard2[2][5]!
- 打!
- battleshipBoard2[2][6]!,
- 沉没!
GO TO FULL VERSION