Comparing Arrays in Java – 在Java中对数组进行比较

最后修改: 2020年 7月 31日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’re going to have a look at different ways to compare arrays in Java. We’ll cover conventional methods, and we’ll also see some examples using lambda expressions.

在本教程中,我们将看看在Java中比较数组的不同方法。我们将介绍传统的方法,也会看到一些使用lambda 表达式的例子。

2. Comparing Arrays

2.比较数组

We’re going to compare arrays in Java, and as we know, these are objects. Therefore, let’s refresh some basic concepts:

我们要在Java中比较数组,正如我们所知,这些都是对象。因此,让我们复习一下一些基本概念。

  • Objects have references and values
  • Two equal references should point to the same value
  • Two different values should have different references
  • Two equal values don’t necessarily have the same references
  • Primitive values only get compared per value
  • String literals only get compared per value

2.1. Comparing Object References

2.1.比较对象引用

If we have two references pointing to the same array, we should always get a result true in an equals comparison with the == operator.

如果我们有两个指向同一个数组的引用,我们应该在用==操作符进行的等价比较中总是得到一个结果true

Let’s look at an example:

我们来看看一个例子。

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = planes1;

First, we created an array of plane models referenced by planes1. We then create planes2, which references planes1. By doing this, we’re creating two references to the same array in memory. Therefore, the “planes1 == planes2” expression will return true.

首先,我们创建了一个由planes1引用的飞机模型阵列。然后我们创建planes2,它引用planes1。通过这样做,我们创建了两个引用 对内存中的同一个数组。因此,“planes1 == planes2”表达式将返回true

For arrays, the equals() method is the same as the == operator. So, planes1.equals(planes2) returns true because both references are referring to the same object. Generally speaking, array1.eqauls(array2) will return true if and only if the expression array1 == array2″ returns true.

对于数组,equals()方法与==运算符相同。所以,planes1.equals(planes2)返回true,因为两个引用都是指同一个对象。一般来说,array1.eqauls(array2)将返回true,当且仅当表达式array1 == array2″返回true

Let’s assert if the two references are the same:

让我们断言这两个参考文献是否相同。

assertThat(planes1).isSameAs(planes2);

Let’s now be sure that the values referenced by planes1 are actually the same as those referenced by planes2. Therefore, we can change the array referenced by planes2, and check if the changes have any impact on the array referenced by planes1:

现在让我们确定planes1所引用的值实际上与planes2所引用的值相同。因此,我们可以改变planes2所引用的数组,并检查这些改变是否对planes1所引用的数组有任何影响。

planes2[0] = "747";

To finally see this working, let’s make our assertions:

为了最终看到这个工作,让我们做出我们的断言。

assertThat(planes1).isSameAs(planes2);
assertThat(planes2[0]).isEqualTo("747");
assertThat(planes1[0]).isEqualTo("747");

With this unit test, we were able to compare two arrays by reference.

通过这个单元测试,我们能够通过引用来比较两个数组。

However, we’ve only proven that one reference, once assigned to the value of another, will reference the same value.

然而,我们只是证明了一个引用一旦被分配到另一个引用的值,就会引用同一个值。

We’ll now create two different arrays with the same values:

我们现在要用相同的值创建两个不同的数组。

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };

Since they are different objects, we know for sure that they are not the same. We can, therefore, compare them:

由于它们是不同的物体,我们肯定知道它们是不一样的。因此,我们可以对它们进行比较。

assertThat(planes1).isNotSameAs(planes2);

To sum up, in this case, we have two arrays in memory that contain the same String values in exactly the same order. However, not only are the referenced arrays different in content, but the references themselves are also different.

总而言之,在这种情况下,我们在内存中有两个数组,它们包含相同的String值,顺序完全相同。然而,不仅被引用的数组在内容上不同,而且引用本身也不同。

2.2. Comparing Array Lengths

2.2.比较阵列的长度

The length of the arrays can be compared regardless of their element types, or whether or not their values are filled in.

数组的长度可以被比较,而不考虑它们的元素类型,或者它们的值是否被填入

Let’s create two arrays:

让我们创建两个数组。

final String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
final Integer[] quantities = new Integer[] { 10, 12, 34, 45, 12, 43, 5, 2 };

These are two different arrays with different element types. In this data set, we’re registering, as an example, how many airplanes of each model are stored in the warehouse. Let’s now run unit tests on them:

这是两个不同的数组,有不同的元素类型。在这个数据集中,我们正在注册,作为一个例子,每个模型的飞机有多少被存储在仓库里。现在让我们对它们运行单元测试。

assertThat(planes1).hasSize(8);
assertThat(quantities).hasSize(8);

With this, we’ve proven that both arrays have eight elements and that the length property returns the correct number of elements for each array.

通过这个,我们已经证明了两个数组都有8个元素,并且length属性为每个数组返回了正确的元素数。

2.3. Comparing Arrays with Arrays.equals

2.3.用Arrays.equals对数组进行比较

So far we only compared arrays based on their object identities. On the other hand, to check if two arrays are equal in terms of their contents, Java provides the Arrays.equals static method. This method will iterate through the arrays, per position in parallel, and apply the == operator, for every pair of elements.

到目前为止,我们只是根据数组的对象身份来比较数组。另一方面,为了检查两个数组在内容上是否相等,Java提供了Arrays.equals静态方法。这个方法将遍历数组,每个位置并行,并应用==运算符,对每一对元素

Let’s create two different arrays with the same String literals in exactly the same order:

让我们用相同的String字元以完全相同的顺序创建两个不同的数组。

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };

And now, let’s assert that they’re equal:

而现在,让我们断言,他们是平等的。

assertThat(Arrays.equals(planes1, planes2)).isTrue();

If we change the order of the values of the second array:

如果我们改变第二个数组的值的顺序。

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "B738", "A320", "A321", "A319", "B77W", "B737", "A333", "A332" };

We’ll get a different result:

我们会得到一个不同的结果。

assertThat(Arrays.equals(planes1, planes2)).isFalse();

2.4. Comparing Arrays with Arrays.deepEquals

2.4.用Arrays.deepEquals对数组进行比较

Using the == operator is easy if we’re using simple types in Java. These could be primitive types or String literals. A comparison between arrays of Objects can be more complicated. The reason behind this is fully explained in our Arrays.deepEquals article. Let’s see an example.

如果我们在Java中使用简单的类型,使用==操作符就很容易。这些可能是原始类型或String字面。在Objects的数组之间进行比较可能会更复杂。这背后的原因在我们的Arrays.deepEquals文章中有充分解释。让我们来看看一个例子。

First, let’s start with a Plane class:

首先,让我们从Plane类开始。

public class Plane {
    private final String name;
    private final String model;

    // getters and setters
}

And, let’s implement the hashCode and equals methods:

而且,让我们实现hashCodeequals方法。

@Override
public boolean equals(Object o) {
    if (this == o)
        return true;
    if (o == null || getClass() != o.getClass())
        return false;
    Plane plane = (Plane) o;
    return Objects.equals(name, plane.name) && Objects.equals(model, plane.model);
}

@Override
public int hashCode() {
    return Objects.hash(name, model);
}

Secondly, let’s create the following two-element arrays:

其次,让我们创建以下两个元素的数组。

Plane[][] planes1 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};
Plane[][] planes2 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};

Let’s now see if they are true, deeply equal arrays:

现在让我们看看它们是否是真正的、深度相等的数组。

assertThat(Arrays.deepEquals(planes1, planes2)).isTrue();

To make sure that our comparison works as  expected, let’s now change the order of our last array:

为了确保我们的比较如期进行,现在让我们改变最后一个数组的顺序。

Plane[][] planes1 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};
Plane[][] planes2 
  = new Plane[][] { new Plane[]{new Plane("Plane 2", "B738")}, new Plane[]{new Plane("Plane 1", "A320") }};

Finally, let’s test if they are indeed not equal anymore:

最后,让我们测试一下它们是否真的不再相等了。

assertThat(Arrays.deepEquals(planes1, planes2)).isFalse();

2.5. Comparing Arrays with Different Orders of Elements

2.5.比较具有不同顺序元素的数组

To check if arrays are equal, regardless of the order of elements, we need to define what makes one instance of our Plane unique. For our case, a different name or model is enough to determine that one plane is different from another. We’ve established this by having already implemented both hashCode and equals methods. This implies that before we can compare our arrays, we should sort them. For that, we need a Comparator:

为了检查数组是否相等,不管元素的顺序如何,我们需要定义是什么使我们的Plane的一个实例变得独一无二。对于我们的情况,不同的名字或模型就足以确定一个平面与另一个平面不同。我们已经通过实现hashCodeequals方法来确定这一点。这意味着在我们比较我们的数组之前,我们应该对它们进行排序。为此,我们需要一个Comparator

Comparator<Plane> planeComparator = (o1, o2) -> {
    if (o1.getName().equals(o2.getName())) {
        return o2.getModel().compareTo(o1.getModel());
    }
    return o2.getName().compareTo(o1.getName());
};

In this Comparator, we’re giving priority to the name. If the names are equal, we solve the ambiguity by looking at the model. We compare strings by using the compareTo method of type String.

在这个比较器中,我们优先考虑名字。如果名字相等,我们通过查看模型来解决模糊不清的问题。我们通过使用compareTo类型的String方法来比较字符串。

We want to be able to find if arrays are equal regardless of the sorting order. To do that, let’s now sort our arrays:

我们希望能够找到数组是否相等,而不管排序顺序如何。为了做到这一点,现在让我们对数组进行排序。

Arrays.sort(planes1[0], planeComparator);
Arrays.sort(planes2[0], planeComparator);

And finally, let’s test them:

最后,让我们测试一下它们。

assertThat(Arrays.deepEquals(planes1, planes2)).isTrue();

Having sorted the arrays in the same order first, we allow the deepEquals method to find if these two arrays are equal.

先将数组按相同的顺序排序后,我们允许使用deepEquals方法来查找这两个数组是否相等。

3. Conclusion

3.总结

In this tutorial, we’ve seen different ways of comparing arrays. Secondly, we saw the difference between comparing references and values. In addition, we’ve taken a look into how we can compare arrays deeply. Finally, we saw the difference between a normal compare and a deep compare using equals and deepEquals, respectively.

在本教程中,我们已经看到了比较数组的不同方法。其次,我们看到了比较引用和值之间的区别。此外,我们还了解了如何对数组进行深度比较。最后,我们看到了分别使用equalsdeepEquals进行普通比较和深度比较的区别。

As always, the full source code for the examples is available over on GitHub.

一如既往,例子的完整源代码可在GitHub上获得