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 == planes2
→ true
✅ 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. 忽略顺序的数组比较
有时我们只关心数组内容是否相同,不关心顺序。此时可以:
- 先对两个数组排序
- 再用
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