Ok, I have heard from many places and sources that whenever I override the equals() method, I need to override the hashCode() method as well. But consider the following piece of code
好吧,我从许多地方和消息来源得知,每当我覆盖equals()方法时,我也需要覆盖hashCode()方法。但请考虑以下代码
package test;
public class MyCustomObject {
int intVal1;
int intVal2;
public MyCustomObject(int val1, int val2){
intVal1 = val1;
intVal2 = val2;
}
public boolean equals(Object obj){
return (((MyCustomObject)obj).intVal1 == this.intVal1) &&
(((MyCustomObject)obj).intVal2 == this.intVal2);
}
public static void main(String a[]){
MyCustomObject m1 = new MyCustomObject(3,5);
MyCustomObject m2 = new MyCustomObject(3,5);
MyCustomObject m3 = new MyCustomObject(4,5);
System.out.println(m1.equals(m2));
System.out.println(m1.equals(m3));
}
}
Here the output is true, false exactly the way I want it to be and I dont care of overriding the hashCode() method at all. This means that hashCode() overriding is an option rather being a mandatory one as everyone says.
这里的输出是真的,完全按照我想要的方式假,我根本不关心覆盖hashCode()方法。这意味着hashCode()覆盖是一个选项而不是每个人都说的强制选项。
I want a second confirmation.
我想要第二次确认。
5 个解决方案
#1
32
It works for you because your code does not use any functionality (HashMap, HashTable) which needs the hashCode()
API.
它适用于您,因为您的代码不使用需要hashCode()API的任何功能(HashMap,HashTable)。
However, you don't know whether your class (presumably not written as a one-off) will be later called in a code that does indeed use its objects as hash key, in which case things will be affected.
但是,您不知道您的类(可能不是一次性写入)将在稍后使用其对象作为哈希键的代码中调用,在这种情况下,事情将受到影响。
As per the documentation for Object class:
根据Object类的文档:
The general contract of hashCode is:
hashCode的一般契约是:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象上的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
#2
11
Because HashMap/Hashtable will lookup object by hashCode() first.
因为HashMap / Hashtable将首先通过hashCode()查找对象。
If they are not the same, hashmap will assert object are not the same and return not exists in the map.
如果它们不相同,则hashmap将断言对象不相同并且返回不存在于地图中。
#3
5
The reason why you need to @Override
neither or both, is because of the way they interrelate with the rest of the API.
您之所以不需要@Override的原因是因为它们与API的其余部分相互关联。
You'll find that if you put m1
into a HashSet<MyCustomObject>
, then it doesn't contains(m2)
. This is inconsistent behavior and can cause a lot of bugs and chaos.
您会发现,如果将m1放入HashSet
The Java library has tons of functionalities. In order to make them work for you, you need to play by the rules, and making sure that equals
and hashCode
are consistent is one of the most important ones.
Java库具有大量功能。为了使它们适合你,你需要遵守规则,并确保equals和hashCode是一致的是最重要的一个。
#4
4
Most of the other comments already gave you the answer: you need to do it because there are collections (ie: HashSet, HashMap) that uses hashCode as an optimization to "index" object instances, an those optimizations expects that if: a.equals(b)
==> a.hashCode() == b.hashCode()
(NOTE that the inverse doesn't hold).
大多数其他评论已经给出了答案:你需要这样做,因为有一些集合(即:HashSet,HashMap)使用hashCode作为“索引”对象实例的优化,这些优化期望如果:a.equals (b)==> a.hashCode()== b.hashCode()(注意反之不成立)。
But as an additional information you can do this exercise:
但作为附加信息,您可以执行此练习:
class Box {
private String value;
/* some boring setters and getters for value */
public int hashCode() { return value.hashCode(); }
public boolean equals(Object obj) {
if (obj != null && getClass().equals(obj.getClass()) {
return ((Box) obj).value.equals(value);
} else { return false; }
}
}
The do this:
这样做:
Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false
What you learn from this example is that implementing equals
or hashCode
with properties that can be changed (mutable) is a really bad idea.
您从这个例子中学到的是,使用可以更改的属性(可变)实现equals或hashCode是一个非常糟糕的主意。
#5
0
It is primarily important when searching for an object using its hashCode() value in a collection (i.e. HashMap, HashSet, etc.). Each object returns a different hashCode() value therefore you must override this method to consistently generate a hashCode value based on the state of the object to help the Collections algorithm locate values on the hash table.
在使用集合中的hashCode()值(即HashMap,HashSet等)搜索对象时,这一点非常重要。每个对象都返回一个不同的hashCode()值,因此您必须重写此方法,以便根据对象的状态始终生成hashCode值,以帮助Collections算法在哈希表上定位值。
#1
32
It works for you because your code does not use any functionality (HashMap, HashTable) which needs the hashCode()
API.
它适用于您,因为您的代码不使用需要hashCode()API的任何功能(HashMap,HashTable)。
However, you don't know whether your class (presumably not written as a one-off) will be later called in a code that does indeed use its objects as hash key, in which case things will be affected.
但是,您不知道您的类(可能不是一次性写入)将在稍后使用其对象作为哈希键的代码中调用,在这种情况下,事情将受到影响。
As per the documentation for Object class:
根据Object类的文档:
The general contract of hashCode is:
hashCode的一般契约是:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象上的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
#2
11
Because HashMap/Hashtable will lookup object by hashCode() first.
因为HashMap / Hashtable将首先通过hashCode()查找对象。
If they are not the same, hashmap will assert object are not the same and return not exists in the map.
如果它们不相同,则hashmap将断言对象不相同并且返回不存在于地图中。
#3
5
The reason why you need to @Override
neither or both, is because of the way they interrelate with the rest of the API.
您之所以不需要@Override的原因是因为它们与API的其余部分相互关联。
You'll find that if you put m1
into a HashSet<MyCustomObject>
, then it doesn't contains(m2)
. This is inconsistent behavior and can cause a lot of bugs and chaos.
您会发现,如果将m1放入HashSet
The Java library has tons of functionalities. In order to make them work for you, you need to play by the rules, and making sure that equals
and hashCode
are consistent is one of the most important ones.
Java库具有大量功能。为了使它们适合你,你需要遵守规则,并确保equals和hashCode是一致的是最重要的一个。
#4
4
Most of the other comments already gave you the answer: you need to do it because there are collections (ie: HashSet, HashMap) that uses hashCode as an optimization to "index" object instances, an those optimizations expects that if: a.equals(b)
==> a.hashCode() == b.hashCode()
(NOTE that the inverse doesn't hold).
大多数其他评论已经给出了答案:你需要这样做,因为有一些集合(即:HashSet,HashMap)使用hashCode作为“索引”对象实例的优化,这些优化期望如果:a.equals (b)==> a.hashCode()== b.hashCode()(注意反之不成立)。
But as an additional information you can do this exercise:
但作为附加信息,您可以执行此练习:
class Box {
private String value;
/* some boring setters and getters for value */
public int hashCode() { return value.hashCode(); }
public boolean equals(Object obj) {
if (obj != null && getClass().equals(obj.getClass()) {
return ((Box) obj).value.equals(value);
} else { return false; }
}
}
The do this:
这样做:
Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false
What you learn from this example is that implementing equals
or hashCode
with properties that can be changed (mutable) is a really bad idea.
您从这个例子中学到的是,使用可以更改的属性(可变)实现equals或hashCode是一个非常糟糕的主意。
#5
0
It is primarily important when searching for an object using its hashCode() value in a collection (i.e. HashMap, HashSet, etc.). Each object returns a different hashCode() value therefore you must override this method to consistently generate a hashCode value based on the state of the object to help the Collections algorithm locate values on the hash table.
在使用集合中的hashCode()值(即HashMap,HashSet等)搜索对象时,这一点非常重要。每个对象都返回一个不同的hashCode()值,因此您必须重写此方法,以便根据对象的状态始终生成hashCode值,以帮助Collections算法在哈希表上定位值。