equals:
- 默认情况下比较对象的引用(即比较它们是否指向内存中的同一个地址);
- 可被重写来比较对象的内容(很多类比如String类、所有包装类(Integer、Double、Boolean等)都重写了equals方法,使得比较这些类的对象时比较的是对象的内容而不是对象的引用);
- 通常不用于基本数据类型的比较,主要用于对象类型的比较,可以比较基本数据类型的包装类对象。
==:
- 比较两个基本数据类型的值是否相同;
- 比较两个对象的引用是否相同;
- 无法通过==直接比较两个对象的内容是否相同。
重写equals()的时候为什么要重写hashCode()
首先我们要知道equals()和hashCode()的约束:
-
如果两个对象相等(根据
equals()
方法),它们的哈希码必须相同。 -
如果两个对象的哈希码不同,它们一定不相等。
-
如果两个对象的哈希码相同,它们可能相等,也可能不相等(需要进一步通过
equals()
方法验证)。
Object类默认hashCode()实现通常返回对象内存地址相关的值,这意味着每个对象都有一个唯一的哈希码,如果我们重写了equals方法,没有重写hashCode方法,那么就可能导致两个对象根据重写自定义的equals方法比较为相等,但它们的哈希码仍可能不同(因为它们的内存地址不同)。此时就可能会违反equals和hashCode的约束。
下面用一个具体的例子来展示:
//创建一个Person类
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 obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}
// 没有重写 hashCode 方法
// @Override
// public int hashCode() {
// return Objects.hash(name, age);
// }
//未重写hashCode导致对象在散列集合中行为异常
public static void main(String[] args) {
Person p1 = new Person("Alice", 30);
Person p2 = new Person("Alice", 30);
System.out.println(p1.equals(p2)); // true
Map<Person, String> map = new HashMap<>();
map.put(p1, "Person 1");
//此时p1和p2通过equals比较是相等的
//但没有重写hashCode就可能导致无法通过同一个key(比较相同)找到对应的value
System.out.println(map.get(p2)); // 如果没有重写 hashCode,这里可能返回 null
}
}