1. 概述
本文深入解析 Java 中 Arrays
类的 deepEquals
方法。我们将探讨它的适用场景,并通过几个典型示例帮助你彻底掌握其使用方式。
如果你还想了解 java.util.Arrays
类中其他常用方法,推荐阅读我们的 Java Arrays 快速指南。
2. 使用目的
✅ 当你需要比较嵌套数组或多维数组是否相等时,deepEquals
是首选方法。
此外,如果数组中包含自定义对象(如 Person
),你还必须重写该类的 equals
方法,否则比较结果可能不符合预期。
⚠️ 注意:deepEquals
的“深比较”特性决定了它会递归遍历所有层级元素,因此性能开销比普通 equals
大,需谨慎在高频场景使用。
2.1. 方法签名
先来看一下核心方法签名:
public static boolean deepEquals(Object[] a1, Object[] a2)
关键点:
- ❌ 不支持基本类型一维数组直接比较(如
int[]
、double[]
等)。 - ✅ 若需比较基本类型数组,应使用对应的包装类(如
Integer[]
)或将数组转为对象数组。 - ✅ 更推荐的做法是:对基本类型的一维数组使用
Arrays.equals()
,它提供了针对各原始类型的重载方法。
2.2. 内部实现机制
deepEquals
的核心优势在于递归深度比较:
- 它不仅比较数组顶层元素,还会逐层深入子数组或嵌套结构。
- 对每个子元素,若仍是数组,则继续调用
deepEquals
进行递归比较。 - 直到遇到非数组对象,才调用其
equals()
方法判断。
⚠️ 踩坑提醒:
避免用于存在自引用(self-reference)的数组结构,否则会触发无限递归,最终抛出 java.lang.StackOverflowError
。
3. 返回结果规则
Arrays.deepEquals
的返回逻辑如下:
条件 | 返回值 |
---|---|
两个数组引用相同(a1 == a2 ) |
✅ true |
两个数组都为 null |
✅ true |
只有一个为 null |
❌ false |
数组长度不同 | ❌ false |
两个数组都为空(长度为0) | ✅ true |
所有对应位置的子元素“深度相等” | ✅ true |
其他不匹配情况 | ❌ false |
“深度相等”指:递归比较每一层元素,直到基本类型或已正确实现
equals
的对象。
4. 实战示例
下面通过几个典型例子,直观展示 deepEquals
与 Arrays.equals
的差异。
4.1. 一维对象数组
先看一个简单的 Object[]
比较:
Object[] anArray = new Object[] { "string1", "string2", "string3" };
Object[] anotherArray = new Object[] { "string1", "string2", "string3" };
assertTrue(Arrays.equals(anArray, anotherArray));
assertTrue(Arrays.deepEquals(anArray, anotherArray));
结果:两个方法都返回 true
。
再测试包含 null
的情况:
Object[] anArray = new Object[] { "string1", null, "string3" };
Object[] anotherArray = new Object[] { "string1", null, "string3" };
assertTrue(Arrays.equals(anArray, anotherArray));
assertTrue(Arrays.deepEquals(anArray, anotherArray));
✅ 结论:deepEquals
支持任意层级的 null
值比较,不会报错。
接下来是重点:嵌套数组场景
Object[] anArray = new Object[] {
"string1",
null,
new String[] {"nestedString1", "nestedString2"}
};
Object[] anotherArray = new Object[] {
"string1",
null,
new String[] {"nestedString1", "nestedString2"}
};
assertFalse(Arrays.equals(anArray, anotherArray)); // ❌ 引用不同
assertTrue(Arrays.deepEquals(anArray, anotherArray)); // ✅ 内容相同
📌 原因分析:
Arrays.equals
只比较顶层元素的引用,而两个子数组是不同对象,引用不等 → 返回false
。deepEquals
发现子元素是数组,会递归调用自身比较内容 → 返回true
。
4.2. 多维基本类型数组
这是最容易踩坑的场景之一。看下面这个二维 int
数组:
int[][] anArray = { { 1, 2, 3 }, { 4, 5, 6, 9 }, { 7 } };
int[][] anotherArray = { { 1, 2, 3 }, { 4, 5, 6, 9 }, { 7 } };
assertFalse(Arrays.equals(anArray, anotherArray)); // ❌
assertTrue(Arrays.deepEquals(anArray, anotherArray)); // ✅
⚠️ 关键点:
Arrays.equals(int[][], int[][])
实际上调用的是Object.equals()
,即比较数组引用。- 虽然内容相同,但两个二维数组是独立创建的对象 → 引用不同 →
equals
返回false
。 deepEquals
则会逐行、逐元素比较int
值 → 内容一致 → 返回true
。
✅ 正确做法:
多维基本类型数组必须用 deepEquals
才能实现内容比较。
4.3. 多维自定义对象数组
现在我们测试包含自定义类的多维数组。
先定义 Person
类,并重写 equals
方法:
class Person {
private int id;
private String name;
private int age;
public Person(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof Person)) return false;
Person person = (Person) obj;
return id == person.id
&& name.equals(person.name)
&& age == person.age;
}
// getter/setter 省略
}
⚠️ 提醒:重写
equals
时务必同时重写hashCode
,避免违反 Java 的equals-hashCode
合约。虽然本例未体现,但生产环境必须遵守。
接下来创建两个内容相同的二维 Person
数组:
Person personArray1[][] = {
{ new Person(1, "John", 22), new Person(2, "Mike", 23) },
{ new Person(3, "Steve", 27), new Person(4, "Gary", 28) }
};
Person personArray2[][] = {
{ new Person(1, "John", 22), new Person(2, "Mike", 23) },
{ new Person(3, "Steve", 27), new Person(4, "Gary", 28) }
};
assertFalse(Arrays.equals(personArray1, personArray2)); // ❌
assertTrue(Arrays.deepEquals(personArray1, personArray2)); // ✅
结果再次验证:deepEquals
能穿透多层结构,调用 Person.equals()
完成内容比对。
小技巧:Objects.deepEquals
还有一个更通用的方法:
assertTrue(Objects.deepEquals(personArray1, personArray2));
✅ Objects.deepEquals(Object a, Object b)
在传入两个数组时,内部会自动委托给 Arrays.deepEquals
,适合泛型或不确定类型时使用。
5. 总结
📌 核心结论:
- ✅ 多维数组 or 嵌套数组的内容比较 → 用
Arrays.deepEquals
- ❌ 一维基本类型数组 → 用
Arrays.equals
- ❌ 一维对象数组(无嵌套)→
Arrays.equals
足够 - ⚠️ 自定义对象必须重写
equals
(和hashCode
) - ⚠️ 避免用于存在循环引用的数组,防止栈溢出
本文完整示例代码已托管至 GitHub:https://github.com/java-tutorials/core-java-arrays-operations-advanced