为什么我需要覆盖 Java 中的 equals 和 hashCode 方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2265503/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do I need to override the equals and hashCode methods in Java?
提问by Shashi
Recently I read through this Developer Works Document.
最近我通读了这个 Developer Works 文档。
The document is all about defining hashCode()
and equals()
effectively and correctly, however I am not able to figure out why we need to override these two methods.
该文档是关于定义hashCode()
和equals()
有效且正确的,但是我无法弄清楚为什么我们需要覆盖这两种方法。
How can I take the decision to implement these methods efficiently?
我如何决定有效地实施这些方法?
采纳答案by Lombo
Joshua Bloch says on Effective Java
Joshua Bloch 谈到 Effective Java
You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object.hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.
您必须在每个覆盖 equals() 的类中覆盖 hashCode()。不这样做将导致违反 Object.hashCode() 的一般契约,这将阻止您的类与所有基于哈希的集合(包括 HashMap、HashSet 和 Hashtable)一起正常运行。
Let's try to understand it with an example of what would happen if we override equals()
without overriding hashCode()
and attempt to use a Map
.
让我们尝试通过一个例子来理解它,如果我们覆盖equals()
而不覆盖hashCode()
并尝试使用Map
.
Say we have a class like this and that two objects of MyClass
are equal if their importantField
is equal (with hashCode()
and equals()
generated by eclipse)
假设我们有一个类像这样那样的两个对象MyClass
是相等的,如果他们importantField
等于(与hashCode()
和equals()
Eclipse生成)
public class MyClass {
private final String importantField;
private final String anotherField;
public MyClass(final String equalField, final String anotherField) {
this.importantField = equalField;
this.anotherField = anotherField;
}
public String getEqualField() {
return importantField;
}
public String getAnotherField() {
return anotherField;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((importantField == null) ? 0 : importantField.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final MyClass other = (MyClass) obj;
if (importantField == null) {
if (other.importantField != null)
return false;
} else if (!importantField.equals(other.importantField))
return false;
return true;
}
}
Override only equals
仅覆盖 equals
If only equals
is overriden, then when you call myMap.put(first,someValue)
first will hash to some bucket and when you call myMap.put(second,someOtherValue)
it will hash to some other bucket (as they have a different hashCode
). So, although they are equal, as they don't hash to the same bucket, the map can't realize it and both of them stay in the map.
如果 onlyequals
被覆盖,那么当您myMap.put(first,someValue)
第一次调用时将散列到某个桶,当您调用myMap.put(second,someOtherValue)
它时将散列到另一个桶(因为它们有不同的hashCode
)。因此,尽管它们相等,但由于它们没有散列到同一个桶中,因此地图无法意识到这一点,并且它们都留在地图中。
Although it is not necessary to override equals()
if we override hashCode()
, let's see what would happen in this particular case where we know that two objects of MyClass
are equal if their importantField
is equal but we do not override equals()
.
虽然没有必要重写equals()
,如果我们超越hashCode()
,让我们看看在这个特殊的情况下会发生什么,我们知道,两个对象MyClass
是相等的,如果他们importantField
相等,但我们不覆盖equals()
。
Override only hashCode
仅覆盖 hashCode
Imagine you have this
想象一下你有这个
MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");
If you only override hashCode
then when you call myMap.put(first,someValue)
it takes first, calculates its hashCode
and stores it in a given bucket. Then when you call myMap.put(second,someOtherValue)
it should replace first with second as per the Map Documentationbecause they are equal (according to the business requirement).
如果您只覆盖,hashCode
那么当您myMap.put(first,someValue)
首先调用它时,计算它hashCode
并将其存储在给定的存储桶中。然后,当您调用myMap.put(second,someOtherValue)
它时,应该根据地图文档将第一个替换为第二个,因为它们是相等的(根据业务需求)。
But the problem is that equals was not redefined, so when the map hashes second
and iterates through the bucket looking if there is an object k
such that second.equals(k)
is true it won't find any as second.equals(first)
will be false
.
但问题是,等于没有重新定义,所以当图哈希second
通过桶和迭代,查找是否有一个对象k
,从而second.equals(k)
是事实,就不会找到任何的second.equals(first)
会false
。
Hope it was clear
希望很清楚
回答by PaulJWilliams
Because if you do not override them you will be use the default implentation in Object.
因为如果您不覆盖它们,您将使用 Object 中的默认实现。
Given that instance equality and hascode values generally require knowledge of what makes up an object they generally will need to be redefined in your class to have any tangible meaning.
鉴于实例相等和 hascode 值通常需要了解构成对象的内容,它们通常需要在您的类中重新定义以具有任何有形意义。
回答by Dewfy
Assume you have class (A) that aggregates two other (B) (C), and you need to store instances of (A) inside hashtable. Default implementation only allows distinguishing of instances, but not by (B) and (C). So two instances of A could be equal, but default wouldn't allow you to compare them in correct way.
假设您有类 (A) 聚合了另外两个 (B) (C),并且您需要将 (A) 的实例存储在哈希表中。默认实现只允许区分实例,而不是通过 (B) 和 (C)。所以 A 的两个实例可能相等,但默认情况下不允许您以正确的方式比较它们。
回答by Ionu? G. Stan
It is useful when using Value Objects. The following is an excerpt from the Portland Pattern Repository:
Examples of value objects are things like numbers, dates, monies and strings. Usually, they are small objects which are used quite widely. Their identity is based on their state rather than on their object identity. This way, you can have multiple copies of the same conceptual value object.
So I can have multiple copies of an object that represents the date 16 Jan 1998. Any of these copies will be equal to each other. For a small object such as this, it is often easier to create new ones and move them around rather than rely on a single object to represent the date.
A value object should always override .equals() in Java (or = in Smalltalk). (Remember to override .hashCode() as well.)
值对象的示例是数字、日期、货币和字符串等。通常,它们是使用相当广泛的小物体。他们的身份基于他们的状态而不是他们的对象身份。这样,您可以拥有同一个概念值对象的多个副本。
因此,我可以拥有代表 1998 年 1 月 16 日的对象的多个副本。这些副本中的任何一个都将彼此相等。对于像这样的小对象,通常更容易创建新对象并移动它们,而不是依赖单个对象来表示日期。
值对象应该总是覆盖 Java 中的 .equals()(或 Smalltalk 中的 =)。(记住也要覆盖 .hashCode() 。)
回答by JuanZe
You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object.hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.
from Effective Java, by Joshua Bloch
您必须在每个覆盖 equals() 的类中覆盖 hashCode()。不这样做将导致违反 Object.hashCode() 的一般契约,这将阻止您的类与所有基于哈希的集合(包括 HashMap、HashSet 和 Hashtable)一起正常运行。
来自Effective Java,作者 Joshua Bloch
By defining equals()
and hashCode()
consistently, you can improve the usability of your classes as keys in hash-based collections. As the API doc for hashCode explains: "This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable
."
通过定义equals()
和hashCode()
一致,您可以提高类作为基于散列集合中的键的可用性。正如 hashCode 的 API 文档所解释的:“支持此方法是为了让java.util.Hashtable
.
The best answer to your question about how to implement these methods efficiently is suggesting you to read Chapter 3 of Effective Java.
关于如何有效地实现这些方法的问题的最佳答案是建议您阅读Effective Java 的第 3 章。
回答by GuruKulki
Both the methods are defined in Object class. And both are in its simplest implementation. So when you need you want add some more implementation to these methods then you have override in your class.
这两种方法都在 Object 类中定义。两者都是最简单的实现。因此,当您需要为这些方法添加更多实现时,您可以在类中进行覆盖。
For Ex: equals() method in object only checks its equality on the reference. So if you need compare its state as well then you can override that as it is done in String class.
例如:对象中的 equals() 方法仅检查其在引用上的相等性。因此,如果您还需要比较它的状态,那么您可以像在 String 类中那样覆盖它。
回答by crunchdog
Simply put, the equals-method in Object check for reference equality, where as two instances of your class could still be semantically equal when the properties are equal. This is for instance important when putting your objects into a container that utilizes equals and hashcode, like HashMapand Set. Let's say we have a class like:
简单地说,Object 中的 equals 方法检查引用是否相等,因为当属性相等时,类的两个实例在语义上仍然是相等的。例如,当将对象放入使用 equals 和 hashcode 的容器(如HashMap和Set )时,这一点很重要。假设我们有一个类:
public class Foo {
String id;
String whatevs;
Foo(String id, String whatevs) {
this.id = id;
this.whatevs = whatevs;
}
}
We create two instances with the same id:
我们创建两个具有相同id 的实例:
Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");
Without overriding equals we are getting:
在不覆盖 equals 的情况下,我们得到:
- a.equals(b) is false because they are two different instances
- a.equals(a) is true since it's the same instance
- b.equals(b) is true since it's the same instance
- a.equals(b) 是假的,因为它们是两个不同的实例
- a.equals(a) 为真,因为它是同一个实例
- b.equals(b) 为真,因为它是同一个实例
Correct? Well maybe, if this is what you want. But let's say we want objects with the same id to be the same object, regardless if it's two different instances. We override the equals (and hashcode):
正确的?好吧,如果这是你想要的。但是假设我们希望具有相同 id 的对象是同一个对象,无论它是否是两个不同的实例。我们覆盖等号(和哈希码):
public class Foo {
String id;
String whatevs;
Foo(String id, String whatevs) {
this.id = id;
this.whatevs = whatevs;
}
@Override
public boolean equals(Object other) {
if (other instanceof Foo) {
return ((Foo)other).id.equals(this.id);
}
}
@Override
public int hashCode() {
return this.id.hashCode();
}
}
As for implementing equals and hashcode I can recommend using Guava's helper methods
至于实现 equals 和 hashcode,我可以推荐使用Guava 的辅助方法
回答by Narinder
I was looking into the explanation " If you only override hashCode then when you call myMap.put(first,someValue)
it takes first, calculates its hashCode and stores it in a given bucket. Then when you call myMap.put(first,someOtherValue)
it should replace first with second as per the Map Documentation because they are equal (according to our definition)." :
我正在研究解释“如果你只覆盖 hashCode 那么当你myMap.put(first,someValue)
首先调用它时,计算它的 hashCode 并将其存储在给定的存储桶中。然后当你调用myMap.put(first,someOtherValue)
它时,应该按照地图文档将 first 替换为 second,因为它们是相等的(根据我们的定义)。” :
I think 2nd time when we are adding in myMap
then it should be the 'second' object like myMap.put(second,someOtherValue)
我认为第二次添加时,myMap
它应该是“第二个”对象,例如myMap.put(second,someOtherValue)
回答by Aarti
The methods equals and hashcode are defined in the object class. By default if the equals method returns true, then the system will go further and check the value of the hash code. If the hash code of the 2 objects is also same only then the objects will be considered as same. So if you override only equals method, then even though the overridden equals method indicates 2 objects to be equal , the system defined hashcode may not indicate that the 2 objects are equal. So we need to override hash code as well.
方法equals 和hashcode 在对象类中定义。默认情况下,如果 equals 方法返回 true,则系统将进一步检查哈希码的值。如果两个对象的哈希码也相同,则仅将对象视为相同。因此,如果您只覆盖 equals 方法,那么即使覆盖的 equals 方法指示 2 个对象相等,系统定义的哈希码也可能不会指示这两个对象相等。所以我们也需要覆盖哈希码。
回答by Rinkal Gupta
hashCode()
:
hashCode()
:
If you only override hash-code method nothing will happen. Because it always return new hashCode
for each object as an Object class.
如果你只覆盖 hash-code 方法,什么都不会发生。因为它总是hashCode
为每个对象返回 new作为 Object 类。
equals()
:
equals()
:
If you only override equal method, a.equals(b)
is true it means the hashCode
of a and b must be same but not happen. Because you did not override hashCode
method.
如果您只覆盖 equal 方法,a.equals(b)
则为 true 意味着hashCode
a 和 b 必须相同但不会发生。因为你没有覆盖hashCode
方法。
Note : hashCode()
method of Object class always return new hashCode
for each object.
注意: hashCode()
Object 类的方法总是hashCode
为每个对象返回新的。
So when you need to use your object in the hashing based collection, must override both equals()
and hashCode()
.
因此,当您需要在基于散列的集合中使用您的对象时,必须同时覆盖equals()
和hashCode()
。