1. 概述

本文将系统性地介绍 Java 中比较数组的不同方法。内容涵盖传统方式,也会结合 Lambda 表达式等现代语法示例,帮助你在实际开发中灵活选择合适的比较策略。

2. 数组比较详解

Java 中的数组本质上是对象,因此理解对象引用与值的比较是基础。我们先快速回顾几个关键点:

  • 对象有引用和值之分
  • 两个引用相等,意味着指向同一块内存
  • 值相同 ≠ 引用相同(典型如字符串常量池)
  • 基本类型只比较值
  • 字符串字面量内容相同即视为相等

接下来我们逐个场景分析。

2.1. 引用比较(== 和 equals)

**如果两个引用指向同一个数组对象,使用 ==equals() 比较结果都为 true**。

来看一个简单例子:

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

这里 planes2 直接赋值为 planes1,相当于两个变量指向同一个数组对象。此时:

planes1 == planes2true
planes1.equals(planes2)true

因为数组类没有重写 equals(),其行为与 == 完全一致。

验证一下:

assertThat(planes1).isSameAs(planes2);

再验证“牵一发而动全身”:

planes2[0] = "747";
assertThat(planes1[0]).isEqualTo("747"); // ✅ 确实同步变了

⚠️ 踩坑提醒:这种“引用相等”不代表内容相等。如果你创建两个内容相同但独立的数组,==equals() 都会返回 false

例如:

String[] planes1 = new String[] { "A320", ... };
String[] planes2 = new String[] { "A320", ... };
assertThat(planes1).isNotSameAs(planes2); // ✅ 不同对象

2.2. 数组长度比较

数组长度比较是最简单的,不关心元素类型,也不关心内容是否填充

示例:

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 };

验证长度:

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

简单粗暴,直接 .length 或断言库的 hasSize() 即可。

2.3. 使用 Arrays.equals 比较内容

要比较两个数组的内容是否完全一致(顺序也必须相同),应使用 Arrays.equals()

它会逐个位置比较元素,对每个元素使用 == 判断。

示例:

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

✅ 断言相等:

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

❌ 一旦顺序不同,结果即为 false

String[] planes2 = new String[] { "B738", "A320", ... };
assertThat(Arrays.equals(planes1, planes2)).isFalse();

⚠️ 注意:对于对象数组,Arrays.equals() 会对每个元素调用 ==不会深入调用 equals() 方法。因此对于自定义对象,可能达不到预期。

2.4. 使用 Arrays.deepEquals 深度比较

当数组元素本身也是数组(多维数组)或包含复杂对象时,Arrays.equals() 就不够用了,必须使用 Arrays.deepEquals()

它会递归地比较每一层,对对象调用其 equals() 方法。

先定义一个 Plane 类:

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

    // 构造、getter、setter 省略
}

并正确实现 equals()hashCode()

@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);
}

创建两个内容相同的二维数组:

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

✅ 深度比较:

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

❌ 如果顺序不同:

Plane[][] planes2 = {
    { new Plane("Plane 2", "B738") },
    { new Plane("Plane 1", "A320") }
};
assertThat(Arrays.deepEquals(planes1, planes2)).isFalse();

2.5. 忽略顺序的数组比较

有时我们只关心数组内容是否相同,不关心顺序。此时可以:

  1. 先对两个数组排序
  2. 再用 Arrays.deepEquals() 比较

前提是元素类实现了 Comparable 或提供 Comparator

定义一个 Comparator

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

排序并比较:

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

✅ 这样即使原始顺序不同,也能判断内容相等。

2.6. 字典序比较(Java 9+)

Java 9 引入了 Arrays.compare() 方法,用于字典序比较两个数组。

  • 返回 0:两数组相等
  • 返回 >0:第一个数组字典序更大
  • 返回 <0:第一个数组字典序更小
  • null 数组始终小于非 null 数组

示例:

@Test
void givenSameContents_whenCompare_thenCorrect() {
    String[] array1 = { "A", "B", "C" };
    String[] array2 = { "A", "B", "C" };
    assertThat(Arrays.compare(array1, array2)).isEqualTo(0);
}

长度不同时,先比长度:

@Test
void givenDifferentContents_whenCompare_thenDifferent() {
    String[] array1 = { "A", "B", "C" };
    String[] array2 = { "A", "C", "B", "D" };

    assertThat(Arrays.compare(array1, array2)).isLessThan(0);  // array1 更短
    assertThat(Arrays.compare(array2, array1)).isGreaterThan(0);
    assertThat(Arrays.compare(array1, null)).isGreaterThan(0); // null 更小
}

📌 Arrays.compare() 有多个重载版本,支持 int[]long[] 等基本类型数组。

3. 总结

场景 推荐方法
引用是否相同 ==equals()
内容是否相同(顺序敏感) Arrays.equals()
多维/对象数组深度比较 Arrays.deepEquals()
忽略顺序比较 先排序 + deepEquals()
字典序比较(Java 9+) Arrays.compare()

✅ 正确选择比较方式,能避免很多“看似相等却判断失败”的坑。尤其在单元测试和集合处理中,务必注意 equals()deepEquals() 的区别。

完整示例代码已托管至 GitHub:https://github.com/yourname/java-array-comparison-demo


原始标题:Comparing Arrays in Java