介绍
一个数组(https://en.wikipedia.org/wiki/Array_(data_structure)允许您组合和存储多个元素。使用数组,您可以存储任何类型的数据,即参考或原始类型。但是,所有的数组元素必须是相同的数据类型。
数组在Java中起着基本的作用,因为许多核心数据类型是基于它们的,例如,常用的参考类型String
实际上是作为一个数组的char
元素实现的,所以即使你可能不知道它,你已经使用了数组。
在本教程中,你将使用一个char
数组来安全地存储密码. 这是数组的常见用例。 一个char
数组比存储密码的string
是一个更好的选择,因为一个string
对象是不可变的 - 也就是说,它不能被压缩。 因此,即使你可能不再需要一个密码string
对象,你不能简单地去除它。 这意味着对象仍然存在于记忆中,因此,攻击者理论上可以访问这个内存部分并阅读密码。 相比之下,你可以很容易地压缩一个作为一个char
数组存储的密码并使其不可用。 因此,攻击者没有机会从检查记忆中学习密码。
前提条件
要遵循本教程,您将需要:
一个环境,你可以运行Java程序跟随的例子. 要在本地机器上设置此设置,你需要以下:
Java (版本 11 或以上) 已安装在您的计算机上,由 Java Development Kit (JDK) 提供的编译器。对于 Ubuntu 和 Debian,请遵循我们教程中 How To Install Java with Apt on Ubuntu 22.04 的 Option 1 的步骤。对于其他操作系统,包括 Mac 和 Windows,请遵循 Java 安装的下载选项。
要编译和运行代码示例,本教程使用 Java Shell,这是从命令行运行的 Read-Evaluate-Print Loop (REPL)。要开始使用 JShell,请检查 [Introduction to JShell]
熟悉 Java 和面向对象的编程,您可以在我们的教程中找到(How To Write Your First Program in Java)(https://andsky.com/tech/tutorials/how-to-write-your-first-program-in-java)。
对 Java 数据类型的理解,这在我们的教程中被讨论了(https://andsky.com/tech/tutorials/understanding-data-types-in-java)。
创建 Arrays
要开始使用一个数组,你必须先创建它. 创建一个数组有几种方法,你创建一个方法取决于你是否知道数组将包含哪些元素。
<$>[info]
信息: 要跟进本教程中的示例代码,请在本地系统上运行jshell
命令,打开Java Shell工具,然后您可以复制、粘贴或编辑示例,在jshell>
提示后添加它们并按ENTER
。
如果您不知道数组元素,则可以创建一个空数组并定义其大小,如下:
1char[] password = new char[6];
在char
关键字之后的[]
组合将变量密码
定义为数组。char
关键字意味着变量包含char
原始词。
当您运行前一个代码时,您将收到以下输出:
1password ==> char[6] { '\000', '\000', '\000', '\000', '\000', '\000' }
输出证实,在名为密码
下创建了一个新的char
数组,它可以存储六个元素([6]),这些元素目前是空的(
000)。
或者,如果您已经知道数组元素,您可以创建一个名为密码
的数组,其中包含char
元素,如下:
1char[] password = new char[] {'s', 'e', 'c', 'r', 'e', 't'};
声明的左部分,在等位符号之前,与第一个空数组示例中的声明的左部分相同 - 一个char
数组被定义为名为password
。声明的第二部分,在等位符号之后,再次以新
关键字开始;然而,元素的数量没有被明确说明。相反,所有六个元素都列出了。
当你将前面的代码插入到jshell中时,你会得到以下输出:
1[secondary_label Output]
2password ==> char[6] { 's', 'e', 'c', 'r', 'e', 't' }
输出确认密码``char
数组已创建并列出其元素。
在后一个示例中,您在创建数组时指定了元素,从而节省了您在为元素编写额外的指示来分配值的机会,这是以这种方式创建数组的好处。
定义和更改数组元素
您不会总是知道数组的元素,所以指定它们以及创建数组可能不是一个选项,无论您是否最初指定数组元素,您可以随时指定或更改它们。
例如,您可以通过引用其索引(即在数组中的位置)来更改密码
数组的元素,如下:
1password[0] = 'n';
通过使用密码[0]
,您指的是密码
数组的第一个元素。 数组元素从0开始编号,所以第一个元素将有0
的索引,就像在这种情况下一样。
在jshell
中执行前一个语句后,您将获得类似于以下的输出:
1[secondary_label Output]
2$8 ==> 'n'
临时变量8美元
在jshell
中被内部使用,在您的情况下可能是一个不同的数字。
在jshell
中,您可以使用一个独特的功能来确认密码
数组已按照您的意图改变。当您粘贴数组的名称时,在jshell
中,它将打印数组及其元素,而无需其他方法:
1password
您将在jshell
中获得以下输出:
1[secondary_label Output]
2password ==> char[6] { 'n', 'e', 'c', 'r', 'e', 't' }
此输出确认您已成功地从s
,e
,c
,r
,e
,t
更改到n
,e
,c
,r
,e
,t
。现在,如果攻击者获得访问您的服务器,他们将获得更改的密码,而不是原始密码。
您将继续在本教程中使用密码
数组,因此出于一致性原因,将第一个元素的值恢复到s
,再次参考它并在jshell
中执行命令:
1password[0] = 's';
这将产生类似于前者与临时变量类似的输出,在这种情况下,25美元
,这确认了更改的成功:
1[secondary_label Output]
2$25 ==> 's'
再次,你有原始的密码
数组,其中包括元素s
,e
,c
,r
,e
,t
。现在你知道如何创建和更改数组的元素,现在是时候开始阅读和使用它的元素了。
获取 Array 元素
获取特定数组元素时,您将使用其索引工作,例如,要获取密码
数组的第二个元素,您可以使用以下代码:
1System.out.println(password[1]);
在此代码中,您使用println()
方法来打印密码
数组的第二个元素。 (有关System.out.println
陈述的更多信息,请参阅我们的教程(How To Write Your First Program in Java)(https://andsky.com/tech/tutorials/how-to-write-your-first-program-in-java#understanding-the-hello-world-program)。
此代码将产生以下输出:
1[secondary_label Output]
2e
输出打印了第二个数组元素e
。就像打印它一样,你可以以任何其他方式使用它,其中一个char
值是合适的。 <!--- AOT 这里的意思不清楚。
此外,您还可以使用前列
循环对所有数组元素进行迭代,正如我们在教程中解释的那样(https://andsky.com/tech/tutorials/how-to-use-loops-in-java)。 循环是控制重复程序流程的结构,而前列循环对于在数组上迭代尤其有用,因为它需要最少的锅板代码。
1for (char c : password) {
2 System.out.print(c);
3}
这个前进
循环在密码
数组上迭代,并使用一个被称为c
的临时char
变量。每次迭代,c
从密码
数组的第一个元素移动到最后一个元素。一旦c
得到数组元素的值,你可以以任何适当的方式在代码块中使用c
。
请注意,‘print()’方法打印了没有新行的论点,相反,到目前为止,在教程中,你已经使用了‘println()’方法,每次运行时都会留下一个新行.<!--AOT 我看不到 println() 方法的例子打印了一个新行,前面的例子只打印了一个元素,即e。我建议添加一个示例显示 println()打印了多个数组元素,这样 println() 和 print() 之间的对比就更清晰了。
如果您准确遵循前面的步骤并在jshell
中运行此代码,您将获得以下输出:
1[secondary_label Output]
2secret
如果您错过了将第一个数组元素从n
返回到s
的步骤,您将获得necret
。
您可以通过将迄今为止所建立的知识结合起来获得数组的所有元素,从此开始,您准备深入到数组的主题,并学习有用的数组方法来执行各种功能。
使用 Arrays 方法
Java 有一个非常有用的Arrays
类,位于java.util
包中。这个类可以帮助您在与数组工作时,通过为常见用例提供有用的方法。这意味着您不必重新发明轮子,您可以节省自己多余的努力。
平等( )的方法
equals()
方法比较两个数组,以确定它们是否等同. 要使两个数组等同,它们必须具有相同的长度、元素和顺序. 继续使用password
数组示例,您将创建一个名为password2
的第二个数组,其中包含字符n
,o
,n
和e
:
1char[] password2 = new char[] {'n', 'o', 'n', 'e'};
一旦在jshell中运行此代码,您将收到以下确认:
1[secondary_label Output]
2password2 ==> char[4] { 'n', 'o', 'n', 'e' }
之前的输出确认你有password2
数组. 它有四个元素,并且它们也被打印出来。 如果你没有退出以前的jshell
会话,你也将有原来的password
数组. 如果你退出你的jshell
会话,你将不得不使用创建数组
中的步骤来重新创建password
数组,以便你可以比较两个数组。
现在你可以比较这两个数组,如下:
1System.out.println(Arrays.equals(password, password2));
在上一行中,您正在使用println()
方法来打印来自Array.equal()
方法的结果,比较password
和password2
数组。
由于两个数组不同,结果将是错误
:
1[secondary_label Output]
2false
输出假
确认两个数组不等。作为一个练习,创建其他数组并比较它们. 如果两个数组相等,你会得到一个真
结果。
类型() 方法
「sort()」方法以上升顺序排序一个数组的元素. 使用此方法,您可以按照字母顺序排列「密码」数组中的字符,运行以下操作:
1Arrays.sort(password);
之后,您可以通过在jshell
中发出其名称来重新打印数组,以便注意它是如何改变的,如下:
1password;
jshell
的输出将是:
1[secondary_label Output]
2password ==> char[6] { 'c', 'e', 'e', 'r', 's', 't' }
这证实了数组仍然有相同的元素,但它们的顺序已经改变了。数组元素已从s
,e
,c
,r
,e
,t
到c
,e
,e
,r
,s
,t
重新排序。改变数组的顺序可能不是一个好主意,因为原来的顺序可能很重要。就像密码
的情况一样,如果您更改顺序,密码与原来的不同,并且不会起作用。
「BinarySearch()」方法
二进制Search()
方法搜索一个数组的元素为一个特定的值。该方法的一个特点是,它需要先排序数组元素;否则,你会得到意想不到的结果。所以,一旦你排序了密码
数组,你可以找到一个元素的索引。例如,你可以找出哪个索引字符c
在密码
中,然后打印它,如下:
1System.out.println(Arrays.binarySearch(password, 'c'));
这将产生:
1[secondary_label Output]
20
请记住,现在密码
数组被排序,并且看起来像这样:c
,e
,e
,r
,s
,t
。由于数字0
被打印,这意味着字符c
具有0
的索引,因为它是第一个数组元素。
「copyOf()」方法
「copyOf()」方法将给定的数组复制到新数组,当您需要增加或减少数组的大小时。 由于数组的长度无法在创建后更改,您可以使用此方法创建具有所需大小的新数组,其中包含从旧数组复制的内容。
例如,密码
数组只能存储六个元素,这不适合当今的安全要求,要增加其大小,您可以使用copyOf()
创建一个新的更大的数组,如下:
1password = Arrays.copyOf(password, 10);
在上面的示例中,您将密码
的值重新分配给一个新的数组。这个新数组是将旧的密码
数组复制到一个长达 10 个元素的新数组的结果。 为了复制它,您使用了Arrays.copyOf()
方法,该方法接受两个参数。
当你在jshell中运行前面的代码时,你会得到类似于此的输出:
1[secondary_label Output]
2password ==> char[10] { 'c', 'e', 'e', 'r', 's', 't', '\000', '\000', '\000', '\000' }
前一行显示密码数组现在有10个元素,前六个元素来自原始的密码
数组,该数组在字母排序后变成了c
,e
,e
,r
,s
,t
。
您也可以通过检查每个数组对象的长度
属性来验证新数组有 10 个元素。
1System.out.println(password.length);
在这里,您使用println()
方法将password.length
作为参数,从jshell
的输出将是:
1[secondary_label Output]
210
本节所涵盖的方法是与数组相关的最有用的方法之一,您可以根据 官方数组文件进一步探索数组
类中的各种方法。
结论
在本教程中,您使用 Java 数组来组合相关项目,您了解如何创建数组,如何查看它们,以及如何使用其内容,您还了解了与数组工作的最佳实践和有用的方法。
關於Java的更多信息,請參閱我們的 如何在Java中編碼系列。