[英]Should to objects which have the same hash be equal?
In this below example, I create two objects which have exactly the same internal structure.在下面的示例中,我创建了两个具有完全相同内部结构的对象。 Both carry nothing but the value 1 as an instance variable.
两者都只携带值 1 作为实例变量。 My thinking is that if I take the hash of
e1
it should be the same as the hash of e2
and therefore e1.equals(e2)
should return true.我的想法是,如果我取
e1
的哈希值,它应该与e2
的哈希值相同,因此e1.equals(e2)
应该返回 true。
class EqualsChecker {
public static void main(String[] args) {
Elem e1 = new Elem(1);
Elem e2 = new Elem(1);
System.out.println(e1); // EqualsChecker$Elem@6ff3c5b5
System.out.println(e2); // EqualsChecker$Elem@3764951d
System.out.println("e1.equals(e2): " + e1.equals(e2)); // returns false
}
static class Elem {
private int v;
public Elem(int i) {
this.v = i;
}
}
}
Why does equals
return false here?为什么这里的
equals
返回 false? I think I have the middle case in the below sketch:我想我在下面的草图中有中间情况:
equals(Object)
's default implementation checks if the two objects are the same instance (ie they are ==
). equals(Object)
的默认实现检查两个对象是否是同一个实例(即它们是==
)。 If you want some different logic, you'll have to implement it yourself.如果你想要一些不同的逻辑,你必须自己实现它。 Note that if you do this, you should also implement your own
hashCode()
, so that two objects that are equal will also have matching hash codes.请注意,如果您这样做,您还应该实现自己的
hashCode()
,以便两个相等的对象也将具有匹配的哈希码。 Eg:例如:
class Elem {
private int v;
@Override
public boolean equals(final Object o) {
if (o == null || this.getClass() != o.getClass()) {
return false;
}
Elem elem = (Elem) o;
return this.v == elem.v;
}
@Override
public int hashCode() {
return this.v;
}
}
Look at the following points from https://docs.oracle.com/javase/9/docs/api/java/lang/Object.html#hashCode--从https://docs.oracle.com/javase/9/docs/api/java/lang/Object.html#hashCode看以下几点——
Now, look at the following code and its output:现在,查看以下代码及其输出:
class MyEmployee {
String code;
String name;
int age;
public MyEmployee(String code, String name, int age) {
super();
this.code = code;
this.name = name;
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
MyEmployee employee1 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee2 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee3 = employee1;
System.out.println(employee1.equals(employee3));
System.out.println("employee1.hashCode(): " + employee1.hashCode());
System.out.println("employee3.hashCode(): " + employee3.hashCode());
System.out.println(employee1.equals(employee2));
System.out.println("employee2.hashCode(): " + employee2.hashCode());
}
}
Output:输出:
true
employee1.hashCode(): 511833308
employee3.hashCode(): 511833308
false
employee2.hashCode(): 1297685781
Since employee3
is pointing to the same object as employee1
, you are getting the same hashcode for them while employee2
is pointing to a different object (although it has the same content, the keyword, new
will create a separate object in the memory) and therefore, you may rarely get the same hashcode for employee2
as point#4 mentioned above from the documentation states: As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects.
由于
employee3
指向同一对象employee1
,你所得到的相同的哈希码为他们而employee2
指向一个不同的对象(尽管它具有相同的内容,关键字, new
会在内存中创建一个单独的对象),因此,您可能很少从文档状态中获得与上面提到的第 4 点相同的employee2
哈希码: As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects.
You must override hashCode
method in a way which should return the same hashcode for two objects having the same content eg您必须以某种方式覆盖
hashCode
方法,该方法应该为具有相同内容的两个对象返回相同的哈希码,例如
class MyEmployee {
String code;
String name;
int age;
public MyEmployee(String code, String name, int age) {
super();
this.code = code;
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((code == null) ? 0 : code.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
}
public class Main {
public static void main(String[] args) {
MyEmployee employee1 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee2 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee3 = employee1;
System.out.println(employee1.equals(employee3));
System.out.println("employee1.hashCode(): " + employee1.hashCode());
System.out.println("employee3.hashCode(): " + employee3.hashCode());
System.out.println(employee1.equals(employee2));
System.out.println("employee2.hashCode(): " + employee2.hashCode());
}
}
Output:输出:
true
employee1.hashCode(): 128107556
employee3.hashCode(): 128107556
false
employee2.hashCode(): 128107556
The implementation of hashCode
given above produces the same hashcode for employee1
and employee2
even though equals
returns false
(check as point#3 mentioned above from the documentation).上面给出的
hashCode
的实现为employee1
和employee2
生成相同的hashcode,即使equals
返回false
(检查文档中提到的第3 点)。
A wrong way of overriding of hashCode
may result in even the same objects returning different hashcodes eg覆盖
hashCode
错误方式可能会导致即使相同的对象返回不同的哈希码,例如
class MyEmployee {
String code;
String name;
int age;
public MyEmployee(String code, String name, int age) {
super();
this.code = code;
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((code == null) ? 0 : (int) (code.length() * (Math.random() * 100)));
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
}
public class Main {
public static void main(String[] args) {
MyEmployee employee1 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee2 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee3 = employee1;
System.out.println(employee1.equals(employee3));
System.out.println("employee1.hashCode(): " + employee1.hashCode());
System.out.println("employee1.hashCode() again: " + employee1.hashCode());
System.out.println("employee3.hashCode(): " + employee3.hashCode());
System.out.println(employee1.equals(employee2));
System.out.println("employee2.hashCode(): " + employee2.hashCode());
}
}
Output:输出:
true
employee1.hashCode(): 66066760
employee1.hashCode() again: 66069457
employee3.hashCode(): 66073797
false
employee2.hashCode(): 66074882
This is the wrong way of overriding hashCode
because invoking hashCode
on the same object more than once during an execution of a Java application must consistently return the same integer (check as point#1 mentioned above from the documentation).这是覆盖
hashCode
的错误方法,因为在 Java 应用程序执行期间多次调用同一个对象上的hashCode
必须始终如一地返回相同的整数(检查文档中提到的第 1 点)。
Now, look at the following code and its output:现在,查看以下代码及其输出:
class MyEmployee {
String code;
String name;
int age;
public MyEmployee(String code, String name, int age) {
super();
this.code = code;
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyEmployee other = (MyEmployee) obj;
if (code == null) {
if (other.code != null)
return false;
} else if (!code.equals(other.code))
return false;
return true;
}
}
public class Main {
public static void main(String[] args) {
MyEmployee employee1 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee2 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee3 = employee1;
System.out.println(employee1.equals(employee3));
System.out.println("employee1.hashCode(): " + employee1.hashCode());
System.out.println("employee3.hashCode(): " + employee3.hashCode());
System.out.println(employee1.equals(employee2));
System.out.println("employee2.hashCode(): " + employee2.hashCode());
}
}
Output:输出:
true
employee1.hashCode(): 511833308
employee3.hashCode(): 511833308
true
employee2.hashCode(): 1297685781
Since employee1.equals(employee2)
returns true
, the hashcode should also be returned same (check point#2 mentioned above from the documentation).由于
employee1.equals(employee2)
返回true
,哈希码也应该返回相同的(检查点#2上面提到的文档)。 However, the hashcode values of employee1
and employee2
are different which is not correct.但是,
employee1
和employee2
的hashcode 值不同,这是不正确的。 This difference is because we haven't overridden the hashCode
method.这种差异是因为我们没有覆盖
hashCode
方法。 So, whenever you override equals
, you should also override hashCode
in a correct way.因此,每当您覆盖
equals
,您还应该以正确的方式覆盖hashCode
。
Finally, given below is a correct way of implementing hashCode
and equals
:最后,下面给出了实现
hashCode
和equals
的正确方法:
class MyEmployee {
String code;
String name;
int age;
public MyEmployee(String code, String name, int age) {
super();
this.code = code;
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((code == null) ? 0 : code.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyEmployee other = (MyEmployee) obj;
if (age != other.age)
return false;
if (code == null) {
if (other.code != null)
return false;
} else if (!code.equals(other.code))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public class Main {
public static void main(String[] args) {
MyEmployee employee1 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee2 = new MyEmployee("AB12", "Dhruv", 24);
MyEmployee employee3 = employee1;
System.out.println(employee1.equals(employee3));
System.out.println("employee1.hashCode(): " + employee1.hashCode());
System.out.println("employee3.hashCode(): " + employee3.hashCode());
System.out.println(employee1.equals(employee2));
System.out.println("employee2.hashCode(): " + employee2.hashCode());
}
}
Output:输出:
true
employee1.hashCode(): 128107556
employee3.hashCode(): 128107556
true
employee2.hashCode(): 128107556
You need to override the equals
method, otherwise the Object
's equals
method will be used to compare the two instances.您需要覆盖
equals
方法,否则将使用Object
的equals
方法来比较两个实例。
@Override
public boolean equals(Object that) {
if (this == that) return true;
if (that instanceof Elem) {
Elem thatElem = (Elem) that;
return thatElem.v == this.v;
}
return false;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.