1. 概述

在Java中,如果我们不恰当地比较两个byte数组,可能会得到意想不到的结果。在这篇简短教程中,我们将学习如何正确地按值比较两个数组。

2. 问题介绍

一个例子可以快速解释这个问题。假设我们有一个字符串:

final static String INPUT = "I am a magic string.";

然后,我们使用String.getBytes()方法从上述字符串获取两个字节数组:

final static byte[] ARRAY1 = INPUT.getBytes();
final static byte[] ARRAY2 = INPUT.getBytes();

显然,如果我们比较ARRAY1ARRAY2,我们期望这两个数组在值上是相等的,因为它们是由相同的输入字符串创建的。

接下来,让我们看看可能犯的常见错误,并找出正确的比较方法。

为了简化,我们将使用单元测试断言来验证每种比较方法是否返回预期结果。

3. ==运算符和equals()方法并非理想选择

在Java中,==称为“等于”运算符。首先,让我们尝试使用*==*运算符比较两个数组:

assertFalse(ARRAY1 == ARRAY2);

上面的简单测试运行时通过了。也就是说,ARRAY1 == ARRAY2返回false,即使两个数组中的元素在值上相同——这并不是我们期望的结果。这是因为==运算符比较的是两个数组的内存地址,而不是它们的内容。这意味着两个数组可以有相同的内容,但它们是不同的对象。因此,即使两个数组等价,==运算符也会返回false

我们可能已经了解了Java中==运算符与equals()方法的区别==执行引用平等检查,而equals()方法执行值平等检查。

由于我们的目标是比较两个数组的值,让我们创建另一个简单的测试,使用equals()方法比较ARRAY1ARRAY2

assertFalse(ARRAY1.equals(ARRAY2));

如果运行这个测试,它也会通过。这意味着equals()方法也没有给出我们期望的结果。接下来,让我们弄清楚为什么equals()没有正确工作。

当我们调用ARRAY1.equals(ARRAY2)时,实际上是调用了Object类的equals()方法。让我们看看Object类的equals()方法的实现:

public boolean equals(Object obj) {
    return (this == obj);
}

如我们所见,Objectequals()方法内部使用==运算符比较两个对象。对于数组,==equals()是一样的,因此它们都执行引用平等检查

4. 使用Arrays.equals()方法

现在我们知道==运算符和equals()方法都不是检查两个数组值等同的正确方式。然而,在Java编程中,两个数组的值比较是一个相当常见的操作。因此,Java标准库提供了Arrays.equals()方法来完成这项任务:

assertTrue(Arrays.equals(ARRAY1, ARRAY2));

如果运行这个方法,测试会通过。所以,Arrays.equals()返回了我们两个byte数组值比较的预期结果。

此外,Arrays.equals()方法适用于其他类型的数组。我们应该使用Arrays.equals()方法来检查所有类型数组的值等同性

最后,让我们看看两个String数组的值比较示例:

String[] strArray1 = new String[] { "Java", "is", "great" };
String[] strArray2 = new String[] { "Java", "is", "great" };

assertFalse(strArray1 == strArray2);
assertFalse(strArray1.equals(strArray2));
assertTrue(Arrays.equals(strArray1, strArray2));

在上面的代码中,strArray1strArray2的内容相同。测试结果显示,*==*equals()报告为false,但使用Arrays.equals()方法给出了预期结果。

5. 总结

在这篇文章中,我们讨论了比较两个数组内容时的常见陷阱。还探讨了如何正确比较两个byte数组的值。

==运算符和equals()方法都对数组执行引用平等检查。如果需要比较两个数组的值,应该使用Arrays.equals(array1, array2)方法。

像往常一样,这里展示的所有代码片段都可以在GitHub上找到。