目录
[示例1:不重写 hashCode 和 equals](#示例1:不重写 hashCode 和 equals)
[示例2:只重写 equals 方法](#示例2:只重写 equals 方法)
[示例3:正确重写 equals 和 hashCode](#示例3:正确重写 equals 和 hashCode)
我将通过几个例子来帮助你理解 hashCode
和 equals
方法的作用和使用场景。
示例1:不重写 hashCode
和 equals
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
System.out.println(p1.equals(p2)); // false
System.out.println(p1.hashCode() == p2.hashCode()); // false
}
}
解释:
- 默认的
equals
方法比较的是对象的引用(是否为同一个对象) - 默认的
hashCode
返回对象的内存地址转换后的整数 - 即使两个对象内容相同,它们也是不同的对象实例
示例2:只重写 equals
方法
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 重写equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && name.equals(person.name);
}
public static void main(String[] args) {
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
System.out.println(p1.equals(p2)); // true
System.out.println(p1.hashCode() == p2.hashCode()); // false
}
}
解释:
- 重写后
equals
根据内容判断为 true - 但
hashCode
仍基于内存地址,导致哈希值不同 - 问题 :这违反了
hashCode
的约定(相等的对象必须有相同的哈希值)
示例3:正确重写 equals
和 hashCode
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 重写equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && name.equals(person.name);
}
// 重写hashCode方法
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public static void main(String[] args) {
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
System.out.println(p1.equals(p2)); // true
System.out.println(p1.hashCode() == p2.hashCode()); // true
}
}
解释:
equals
根据内容判断对象是否相等hashCode
根据内容计算哈希值- 符合 Java 规范:相等的对象必须有相同的哈希值
示例4:在哈希集合中的行为
import java.util.HashSet;
import java.util.Set;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && name.equals(person.name);
}
@Override
public int hashCode() {
return name.hashCode() + age;
}
public static void main(String[] args) {
Set<Person> set = new HashSet<>();
set.add(new Person("Bob", 30));
set.add(new Person("Bob", 30));
System.out.println(set.size()); // 1
}
}
解释:
- 由于正确重写了
equals
和hashCode
- HashSet 能够正确判断两个内容相同的对象为重复元素
- 如果没有正确重写这两个方法,Set 会包含重复元素
关键规则总结:
- equals 的约定:
-
- 自反性:x.equals(x) 必须为 true
- 对称性:x.equals(y) 为 true 时,y.equals(x) 也必须为 true
- 传递性:如果 x.equals(y) 和 y.equals(z) 为 true,则 x.equals(z) 也必须为 true
- 一致性:多次调用 x.equals(y) 结果不变
- 任何非 null 对象与 null 比较结果为 false
- hashCode 的约定:
-
- 相等的对象必须具有相同的哈希值
- 哈希值在对象的生命周期内不应改变
- 不相等的对象可以有相同的哈希值(哈希冲突)
- 最佳实践:
-
- 当重写
equals
方法时,必须重写hashCode
方法 - 使用相同的字段来计算
equals
和hashCode
- 可以使用
Objects.hash()
方法简化hashCode
的实现
- 当重写