在 Java 中,Object 类是所有类的根类,equals() 和 hashCode() 是 Object 类中非常重要的两个方法。它们在对象比较和集合框架(如 HashMap, HashSet 等)中扮演着关键角色。理解这两个方法的作用以及如何正确地重写它们是编写健壮 Java 代码的基础。
1. equals() 方法
-
定义:
equals()方法用于比较两个对象的“内容”是否相等。默认情况下,Object类中的equals()方法比较的是对象的引用(即两个对象是否是同一个对象)。 -
默认实现:
public boolean equals(Object obj) { return (this == obj); }这意味着如果你不重写
equals()方法,equals()的默认实现将返回true仅当两个引用指向同一个对象。 -
重写
equals(): 如果你希望按照对象的内容(例如属性值)来比较两个对象是否相等,则需要重写equals()方法。 -
重写时的规则:
- 自反性: 对于任何非空引用值
x,x.equals(x)必须返回true。 - 对称性: 对于任何非空引用值
x和y,x.equals(y)必须返回true,则y.equals(x)也必须返回true。 - 传递性: 对于任何非空引用值
x,y,z,如果x.equals(y)返回true,且y.equals(z)返回true,那么x.equals(z)必须返回true。 - 一致性: 对于任何非空引用值
x和y,在对象未被修改的情况下,多次调用x.equals(y)应返回相同的结果。 - 非空性: 对于任何非空引用值
x,x.equals(null)必须返回false。
- 自反性: 对于任何非空引用值
-
示例:
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 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); } @Override public int hashCode() { return Objects.hash(name, age); } }
2. hashCode() 方法
-
定义:
hashCode()方法返回对象的哈希码,哈希码是一个整数,通常用于提高基于哈希的集合的效率(如HashMap,HashSet等)。hashCode()方法用于在集合中快速定位对象。 -
默认实现:
Object类中的hashCode()方法返回一个由对象的内存地址转换而来的整数。
-
重写
hashCode():- 如果你重写了
equals()方法,你几乎总是需要重写hashCode()方法,以确保在使用基于哈希的集合(如HashMap,HashSet)时,两个相等的对象(根据equals()判断)也具有相同的哈希码。
- 如果你重写了
-
hashCode()和equals()的关系:- 如果两个对象根据
equals()方法是相等的,那么它们的hashCode()必须相同。 - 如果两个对象的
hashCode()相同,它们并不一定根据equals()方法相等,但在集合中会被放在同一个“桶”中。 - 如果两个对象的
hashCode()不同,那么它们肯定不相等。
- 如果两个对象根据
-
重写
hashCode()时的技巧:- 使用类的多个重要属性来计算哈希码,以减少哈希冲突。
Java 7及以上版本可以使用Objects.hash()方法来简化哈希码的计算。
-
示例:
@Override public int hashCode() { return Objects.hash(name, age); // 使用对象的属性生成哈希码 }
3. 使用时的注意事项
- 一致性:
equals()和hashCode()的实现必须保持一致性。如果两个对象根据equals()方法是相等的,那么它们的hashCode()必须相等。否则,会导致集合如HashMap和HashSet无法正确工作。 - 不要仅仅依赖于自动生成: 虽然现代 IDE 可以自动生成
equals()和hashCode(),但你应确保生成的代码符合对象逻辑上的相等性要求,并考虑到未来属性的更改。
4. 使用技巧
Objects.equals()和Objects.hash()方法:当你重写equals()和hashCode()时,使用Objects.equals()来比较属性值可以避免空指针异常;使用Objects.hash()来计算哈希值可以简化代码。- 组合类中的
equals()和hashCode(): 在有多个类组合成一个类时,确保equals()和hashCode()的实现包含所有重要的组合属性,以避免逻辑上的错误。 hashCode()的缓存: 如果对象是不可变的,可以考虑将hashCode()的结果缓存起来,以避免重复计算。
5. 常见问题
- 未正确重写
equals()和hashCode():当你仅重写equals()而未重写hashCode()时,在使用基于哈希的集合时会出现不一致行为。例如,两个相等的对象可能不会出现在同一个HashSet中,因为它们的哈希码不同。 - 哈希冲突: 当多个对象的
hashCode()相同但equals()不相等时,哈希冲突会降低基于哈希的集合的性能。这就是为什么良好的哈希码设计和尽量避免冲突非常重要。
小结
equals()用于比较对象的内容是否相等,必须遵循自反性、对称性、传递性、一致性和非空性原则。hashCode()返回对象的哈希码,用于基于哈希的集合中。它必须与equals()方法保持一致。- 在集合中使用时,确保两个相等的对象(根据
equals()判断)有相同的哈希码。 - 重写这两个方法时,应仔细考虑对象的逻辑相等性,避免常见错误。
通过理解和正确使用 equals() 和 hashCode(),可以避免许多在 Java 编程中容易出现的错误,特别是在使用集合框架时。

4103

被折叠的 条评论
为什么被折叠?



