Java数组教程:掌握声明、初始化与操作技巧
简介
数组允许您将多个元素分组和存储。使用数组,您可以存储任何类型的数据,包括引用类型或原始类型。然而,所有的数组元素必须是相同的数据类型。数组的数据类型在创建数组时声明,不能更改。类似地,数组的长度(即可以存储多少元素)也在开始时定义,并且不能更改。
在Java中,数组发挥了基础作用,因为许多核心数据类型都是基于它们构建的。例如,频繁使用的引用类型String
实际上是由char
元素的数组实现的。所以即使您可能不知道,您已经使用过数组了。
在本教程中,您将使用一个char
数组来安全地存储密码。这是数组的一个常见用例。char
数组是比String
更好的存储密码的选择,因为String
对象是不可变的——也就是说,它不能被覆盖。因此,即使您可能不再需要一个密码String
对象,您也无法直接处理掉它。这意味着该对象会保留在内存中,结果是攻击者理论上可以访问这部分内存并读取密码。相比之下,您可以轻松地覆盖存储为char
数组的密码,使其无法使用。因此,攻击者没有机会通过检查内存来获取密码。
先决条件
要学习本教程,您需要:
- 一个可以执行Java程序的环境,以便跟随示例。要在您的本地机器上设置此环境,您需要:
- 机器上安装了Java(版本11或更高),并带有Java开发工具包(JDK)提供的编译器。对于Ubuntu和Debian,请遵循我们教程《如何在Ubuntu 22.04上使用Apt安装Java》中选项1的步骤。对于包括Mac和Windows在内的其他操作系统,请遵循Java安装的下载选项。
- 为了编译和运行代码示例,本教程使用Java Shell,它是一个从命令行运行的读取-评估-打印循环(REPL)。要开始使用JShell,请查看《JShell入门指南》。为避免重复说明,所有示例都在一个JShell会话中执行并使用相同的变量。
- 熟悉Java和面向对象编程,您可以在我们的教程《如何编写您的第一个Java程序》中找到相关内容。
- 理解Java数据类型,这在我们的教程《理解Java数据类型》中有所讨论。
创建数组
要开始使用数组,您必须首先创建它。有几种方法可以创建数组,创建方式取决于您是否知道数组将包含哪些元素。
信息:要跟随本教程中的示例代码,请通过运行jshell
命令在您的本地系统上打开Java Shell工具。然后,您可以复制、粘贴或编辑示例,将其添加到jshell>
提示符后并按回车键。要退出jshell,请键入/exit
。
这是文章《如何在Java中使用数组》的第2部分(共6部分)。
如果您不知道数组元素,可以创建一个空数组并定义其大小,如下所示:
- char[] password = new char[6];
char
关键字后的 []
组合将变量 password
定义为一个数组。char
关键字表示该变量存储字符基本类型。要创建数组对象,您可以使用 new
关键字,并将数组定义为 char[6]
,这意味着它是一个包含六个字符基本类型元素的数组。
运行上述代码后,您将收到以下输出:
- password ==> char[6] { '\000', '\000', '\000', '\000', '\000', '\000' }
输出确认已创建一个名为 password
的新字符数组。它可以存储六个元素([6]
),这些元素目前为空(\000
)。
或者,如果您已经知道数组元素,可以创建一个名为 password
的字符数组,如下所示:
- char[] password = new char[] {'s', 'e', 'c', 'r', 'e', 't'};
语句等号左侧的部分与第一个空数组示例中的语句左侧部分相同——定义了一个名为 password
的字符数组。语句等号右侧的第二部分再次以 new
关键字开头;但是,元素的数量没有明确给出。相反,所有六个元素都已列出。列表以左括号开头,后跟六个元素。由于元素是字符基本类型,它们用单引号('
)括起来。列表以右括号结束。
当您将上述代码粘贴到 jshell 中时,您将获得以下输出:
password ==> char[6] { 's', 'e', 'c', 'r', 'e', 't' }
输出确认 password
字符数组已创建,并且其元素已列出。
在后一个示例中,您在创建数组时指定了元素。这使您无需编写额外的指令来为元素赋值。这就是以这种方式创建数组的好处。或者,您可以编写代码来填充元素,每个新元素都单独定义。接下来您将进行此操作。
指定和修改数组元素
这是文章《如何在Java中使用数组》的第3部分(共6部分)。
您并非总能预先知道数组中的所有元素,因此在创建数组时就指定它们可能不是一个可行的选择。无论您最初是否指定了数组元素,您都可以随时在后续操作中指定或更改它们。
例如,您可以通过引用密码数组的索引(即它在数组中的位置)来更改其元素,如下所示:
- password[0] = ‘n’;
通过使用 password[0]
,您正在引用 password
数组的第一个元素。数组元素从索引 0 开始编号,因此第一个元素的索引为 0,如本例所示。数组元素的索引号始终用方括号 []
括起来。您重新定义了数组元素并为其分配了一个新值——字符原始类型 'n'
。
在 jshell 中执行上述语句后,您将获得类似于以下内容的输出:
$8 ==> ‘n’
临时变量 $8
在 jshell 内部使用。在您的情况下,它可能是一个不同的数字。
jshell 中有一个独特的功能,您可以使用它来确认 password
数组是否已按您预期的方式更改。当您在 jshell 中粘贴数组的名称(在本例中为 password
)时,它将打印数组及其元素,而无需额外的方法:
- password
您将在 jshell 中获得以下输出:
password ==> char[6] { ‘n’, ‘e’, ‘c’, ‘r’, ‘e’, ‘t’ }
此输出确认您已成功将 password
字符数组从 ‘s’, ‘e’, ‘c’, ‘r’, ‘e’, ‘t’ 更改为 ‘n’, ‘e’, ‘c’, ‘r’, ‘e’, ‘t’。现在,如果攻击者获得对您服务器的访问权限,他们将获得更改后的密码而不是原始密码。或者,如果您使用 String
变量存储密码,即使您为其重新分配了新值,旧值对象仍将在内存中保留一段时间,攻击者可能会读取它。
在本教程中,您将继续使用 password
数组,因此为了保持一致性,请通过再次引用它并在 jshell 中执行命令,将第一个元素的值恢复为 ‘s’:
- password[0] = ‘s’;
这将产生类似于前面带有临时变量的输出(在本例中为 $25
),这确认更改成功:
$25 ==> ‘s’
您再次拥有原始的 password
数组,其元素为 ‘s’, ‘e’, ‘c’, ‘r’, ‘e’, ‘t’。现在您已经知道如何创建和修改数组的元素,是时候开始读取和使用其元素了。
获取数组元素
当获取特定的数组元素时,您将使用其索引。例如,要获取 password
数组的第二个元素,您可以使用以下代码:
- System.out.println(password[1]);
在此代码中,您使用 println()
方法打印 password
数组的第二个元素。(有关 System.out.println
语句的更多信息,请查看我们的教程《如何在Java中编写您的第一个程序》。)第二个元素的索引为 1,因为如前所述,数组元素从 0 开始编号。
此代码将产生以下输出:
e
输出打印了第二个数组元素 e
。就像打印它一样,您可以在任何适合 char
值的地方使用它。
此外,您还可以使用 foreach
循环遍历所有数组元素,如我们的教程《如何在Java中使用循环》中所述。循环是一种控制重复程序流程的结构,而 foreach
循环对于遍历数组特别有用,因为它需要最少的样板代码。以下是一个示例:
- for (char c : password) {
- System.out.print(c);
- }
这个 foreach
循环遍历 password
数组,并使用一个名为 c
的临时 char
变量。在每次迭代中,c
从 password
数组的第一个元素移动到最后一个元素。一旦 c
获得数组元素的值,您就可以在代码块内以任何合适的方式使用 c
。在前面的示例中,您使用 print()
方法打印 c
。
请注意,print()
方法打印参数时不带换行符。相比之下,到目前为止的教程中,您一直使用 println()
方法,该方法每次运行时都会留下一个新行。在这种情况下,print()
更适合,因为它会将 password
数组中的所有元素打印在同一行上,结果将更好地可视化为一个单词(“secret”)。
如果您严格按照前面的步骤操作并在 jshell 中运行此代码,您将获得以下输出:
secret
如果您忘记了将第一个数组元素从 n
重置回 s
的步骤,您将得到 necret
而不是 secret
。
结合您目前所学的知识,您可以获取数组的所有元素。从现在开始,您已准备好深入研究数组主题并学习用于执行各种功能的有用数组方法。
使用数组方法
Java 在 java.util
包中有一个非常有用的 Arrays
类。这个类通过提供用于常见用例的有用方法来帮助您处理数组。这意味着您不必重复造轮子,可以节省冗余的工作。以下是一些最常用的方法:
equals() 方法
这是文章《如何在Java中使用数组》的第5部分(共6部分)。
equals()
方法用于比较两个数组是否相等。要使两个数组相等,它们必须具有相同的长度、元素和顺序。继续以密码数组为例,您将创建一个名为 password2
的第二个数组,其中包含字符 ‘n’、’o’、’n’ 和 ‘e’:
- char[] password2 = new char[] {‘n’, ‘o’, ‘n’, ‘e’};
在 jshell 中运行此代码后,您将获得以下确认:
password2 ==> char[4] { 'n', 'o', 'n', 'e' }
上述输出确认您已拥有 password2
数组。它有四个元素,并且这些元素也已打印出来。如果您尚未退出之前的 jshell 会话,您还将拥有原始的 password
数组。如果您已退出 jshell 会话,则必须使用“创建数组”中的步骤重新创建 password
数组,以便您拥有两个可以比较的数组。
现在您可以比较这两个数组,如下所示:
- System.out.println(Arrays.equals(password, password2));
在上面这行代码中,您正在使用 println()
方法打印 Arrays.equals()
方法比较 password
和 password2
数组的结果。
由于这两个数组不同,结果将为 false
:
false
输出 false
确认这两个数组不相等。作为练习,创建其他数组并进行比较。如果两个数组相等,您将得到 true
结果。
sort()
方法
sort()
方法按升序对数组元素进行排序。使用此方法,您可以通过运行以下代码将 password
数组中的字符按字母顺序排列:
- Arrays.sort(password);
之后,您可以通过在 jshell 中直接输入数组名称来再次打印数组,以查看其变化,如下所示:
- password;
jshell 的输出将是:
password ==> char[6] { 'c', 'e', 'e', 'r', 's', 't' }
这证实了数组仍然包含相同的元素,但它们的顺序已改变。数组元素从 ‘s’, ‘e’, ‘c’, ‘r’, ‘e’, ‘t’ 重新排序为 ‘c’, ‘e’, ‘e’, ‘r’, ‘s’, ‘t’。像这样改变数组的顺序可能不是一个好主意,因为原始顺序可能很重要。就像密码的情况一样,如果您改变顺序,密码将与原始密码不同,并且将无法使用。然而,在其他用例中,数组元素的顺序可能不重要,并且可能需要初始排序,您将在接下来了解到。
binarySearch()
方法
这是文章《如何在Java中使用数组》的第6部分(共6部分)。
binarySearch()
方法用于在数组元素中搜索给定值。该方法的一个特殊之处在于,它要求数组元素必须首先进行排序;否则,您将获得意想不到的结果。因此,一旦您对 password
数组进行了排序,就可以查找元素的索引。例如,您可以查找字符 'c'
在 password
数组中的索引并打印出来,如下所示:
- System.out.println(Arrays.binarySearch(password, ‘c’));
这将产生:
0
回想一下,password
数组现在已排序,看起来像这样:’c’, ‘e’, ‘e’, ‘r’, ‘s’, ‘t’。由于打印的数字是 0,这意味着字符 ‘c’ 的索引是 0,因为它是第一个数组元素。
copyOf()
方法
当您需要增加或减少数组大小时,copyOf()
方法会将给定数组复制到一个新数组中。由于数组的长度在创建后无法更改,因此您可以使用此方法创建一个具有所需大小的新数组,其中包含从旧数组复制的内容。
例如,password
数组只能存储六个元素,这不适合当今的安全要求。要增加其大小,您可以使用 copyOf()
创建一个更大的新数组,如下所示:
- password = Arrays.copyOf(password, 10);
在前面的示例中,您将 password
的值重新分配给一个新数组。这个新数组是将旧的 password
数组复制到一个长度为 10 个元素的新数组的结果。为了复制它,您使用了 Arrays.copyOf()
方法,该方法接受两个参数。第一个参数是您要从中复制的数组。第二个参数是您正在创建的新数组的长度。
当您在 jshell 中运行前面的代码时,您将获得类似以下的输出:
password ==> char[10] { ‘c’, ‘e’, ‘e’, ‘r’, ‘s’, ‘t’, ‘\000’, ‘\000’, ‘\000’, ‘\000’ }
上面一行显示 password
数组现在有 10 个元素。前六个元素来自原始的 password
数组,在按字母排序后,它们变成了 ‘c’, ‘e’, ‘e’, ‘r’, ‘s’, ‘t’。最后四个值是空的,因为 Arrays.copyOf()
在增加元素数量时会用空值填充新元素。
您还可以通过检查每个数组对象都具有的 length
属性来验证新数组是否包含 10 个元素。您可以按常规方式打印此值:
- System.out.println(password.length);
在这里,您使用 println()
方法并将 password.length
作为参数传递。jshell 的输出将是:
10
本节介绍的方法是与数组相关的一些最有用的方法。您可以根据官方的 Arrays
文档,进一步探索 Arrays
类中的各种方法。
总结
在本教程中,您使用 Java 数组对相关项进行分组。您学习了如何创建数组、如何查看它们以及如何使用其内容。您还学习了使用数组的最佳实践和有用方法。
有关 Java 的更多内容,请查看我们的《Java 编程系列教程》。