题目
Java中==和equals()的区别及重写equals()的规范
信息
- 类型:问答
- 难度:⭐⭐
考点
对象比较,equals方法重写,==运算符,hashCode契约
快速回答
核心区别:
- ==运算符:比较对象内存地址(引用相等)或基本类型值
- equals()方法:默认比较引用,但通常被重写为比较对象内容(逻辑相等)
重写规范:
- 重写equals()必须同时重写hashCode()
- 遵循自反性、对称性、传递性、一致性
- 处理null和类型检查
一、核心区别
==运算符:
- 对基本类型(int, char等)比较值
- 对引用类型比较内存地址(是否同一对象)
- 示例:
String a = new String("abc"); String b = new String("abc"); a == b; // false(不同对象)
equals()方法:
- Object类默认实现等同于==
- 通常被重写实现逻辑相等(如String比较字符内容)
- 示例:
a.equals(b); // true(内容相同)
二、重写equals()规范
正确重写示例:
class Person {
private String name;
private int age;
@Override
public boolean equals(Object o) {
// 1. 自反性
if (this == o) return true;
// 2. 非空和类型检查
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
// 3. 比较关键字段
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
// 4. 必须重写hashCode(重要!)
return Objects.hash(name, age);
}
}三、必须遵守的契约
- 自反性:x.equals(x) 必须为true
- 对称性:x.equals(y) 与 y.equals(x) 结果相同
- 传递性:x.equals(y)且y.equals(z) 则 x.equals(z)
- 一致性:多次调用结果不变(不依赖可变字段)
- 非空性:x.equals(null) 必须返回false
四、常见错误
- 未重写hashCode:导致HashMap/HashSet行为异常
// 错误示例:只重写equals不重写hashCode Set<Person> set = new HashSet<>(); set.add(new Person("Tom", 20)); set.contains(new Person("Tom", 20)); // 可能返回false - 违反对称性:
// 错误示例 class A { boolean equals(B b) { ... } // 参数类型错误! } - 比较可变字段:对象放入集合后修改字段导致找不到
五、最佳实践
- 使用IDE自动生成equals/hashCode(如IntelliJ/ECJ)
- 优先使用Objects.equals()比较字段避免NPE
- 对于不可变类(如String),字段比较是安全的
- 数组比较用Arrays.equals()
六、扩展知识
- hashCode契约:相等对象必须有相同hashCode,但反之不成立
- instanceof vs getClass():
getClass()要求严格类型匹配,instanceof支持子类(需根据设计选择) - Objects.equals():安全处理null的比较工具方法