为特定条件维护 hashCode 合同,equals() 取决于两个整数
Maintaining hashCode contract for the specific condition, equals() depending on two integers
我有一个基本的 class 结构:
class Employee {
int eId;
String eName;
Employee(int id, String name) {
this.eId= id;
this.eName= name;
}
相等的条件是 equals()
应该 return 为真,如果 任何 为真:
eId
相同
eName
相同
eName
的长度相同。
我在覆盖 equals()
时没有问题,但是,为了维护哈希码合同,我也应该覆盖 hashCode()
。因此,hashCode 应该取决于 eId
和 eName.length()
(如果 eName
相等,则它们的长度也相等)。所以有四种情况:
Employee e1 = new Employee(4, "John");
Employee e2 = new Employee(3, "Jane");
Employee e3 = new Employee(4, "Jim");
Employee e4 = new Employee(7, "Random");
hashCode()
应 return e1
、e2
和 e3
的相同值以及 e4
的不同值。我想不出满足这个要求的逻辑。
这是确切的问题:
Create a class (having parameters name, id etc). Show that if 2 objects of this class will be compared then they should return true in any of below case :
A. Id of both are same.
B. Name of both are same.
C. Length of name’s of both are same.
Make sure HashCode contract should not violate.
如果你使用Java 7,那么我认为使用java.util.Objects很容易:
@Override
public int hashCode() {
return Objects.hash(eld,eName.length());
}
或者你可以考虑Guava,在com.google.common.base.Objects
下也有同样的方法
您 运行 遇到了麻烦,因为您的平等观念不一致。具体来说,它不是可传递的,.equals()
的合同要求。
It is transitive: for any non-null reference values x
, y
, and z
, if x.equals(y)
returns true
and y.equals(z)
returns true
, then x.equals(z)
should return true
.
根据您的定义,e1
等于 e2
和 e3
,但 e2
不等于 e3
。这与 Java 的平等概念不相容。这也是为什么您 运行 在定义合理的 .hashCode()
实现时遇到麻烦。
然而,如果您使用的是 Guava,您可以定义自定义 Comparator
(or Ordering
。对于大多数用例(如排序、搜索或过滤),您应该能够像使用 .equals()
方法一样使用单独的 Comparator
实例。您实际上是在尝试定义 等效 对象,而不是 相等 对象。
如果您出于任何原因不能使用单独的 Comparator
,您的 Employee
对象将根本不一致,即使您应该得到 "workable" .hashCode()
实施。
我想,你不能在你的情况下写一个一致的 hashCode
,因为你的 equals
违反了 Object.equals
方法的契约,即传递性:
It is transitive: for any non-null reference values x
, y
, and z
, if x.equals(y)
returns true
and y.equals(z)
returns true
, then x.equals(z)
should return true
.
假设你有这个代码:
Employee a = new Employee(1, "John");
Employee b = new Employee(1, "James");
Employee c = new Employee(2, "James");
在这种情况下,您的等于运算 a.equals(b)
和 b.equals(c)
,而不是 a.equals(c)
。
我建议重新考虑 equals
的实施。可能您的 Employee
定义了 eId
或 eName
,因此最好添加一个 boolean
字段来说明是 eId
还是 eName
应该使用。这样你就可以轻松实现equals
和hashCode
。这样的实现可能是这样的(为简单起见,假设 eName
不能是 null
):
class Employee {
boolean useName;
int eId = 0;
String eName;
Employee(int id) {
this.eId = id;
this.useName = false;
}
Employee(String name) {
this.eName = name;
this.useName = true;
}
@Override
public int hashCode() {
return useName ? eName.length() * 1337 : eId * 7331;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (useName != other.useName)
return false;
if (useName) {
if (eName.length() != other.eName.length())
return false;
} else {
if (eId != other.eId)
return false;
}
return true;
}
}
我有一个基本的 class 结构:
class Employee {
int eId;
String eName;
Employee(int id, String name) {
this.eId= id;
this.eName= name;
}
相等的条件是 equals()
应该 return 为真,如果 任何 为真:
eId
相同eName
相同eName
的长度相同。
我在覆盖 equals()
时没有问题,但是,为了维护哈希码合同,我也应该覆盖 hashCode()
。因此,hashCode 应该取决于 eId
和 eName.length()
(如果 eName
相等,则它们的长度也相等)。所以有四种情况:
Employee e1 = new Employee(4, "John");
Employee e2 = new Employee(3, "Jane");
Employee e3 = new Employee(4, "Jim");
Employee e4 = new Employee(7, "Random");
hashCode()
应 return e1
、e2
和 e3
的相同值以及 e4
的不同值。我想不出满足这个要求的逻辑。
这是确切的问题:
Create a class (having parameters name, id etc). Show that if 2 objects of this class will be compared then they should return true in any of below case :
A. Id of both are same.
B. Name of both are same.
C. Length of name’s of both are same.
Make sure HashCode contract should not violate.
如果你使用Java 7,那么我认为使用java.util.Objects很容易:
@Override
public int hashCode() {
return Objects.hash(eld,eName.length());
}
或者你可以考虑Guava,在com.google.common.base.Objects
您 运行 遇到了麻烦,因为您的平等观念不一致。具体来说,它不是可传递的,.equals()
的合同要求。
It is transitive: for any non-null reference values
x
,y
, andz
, ifx.equals(y)
returnstrue
andy.equals(z)
returnstrue
, thenx.equals(z)
should returntrue
.
根据您的定义,e1
等于 e2
和 e3
,但 e2
不等于 e3
。这与 Java 的平等概念不相容。这也是为什么您 运行 在定义合理的 .hashCode()
实现时遇到麻烦。
然而,如果您使用的是 Guava,您可以定义自定义 Comparator
(or Ordering
。对于大多数用例(如排序、搜索或过滤),您应该能够像使用 .equals()
方法一样使用单独的 Comparator
实例。您实际上是在尝试定义 等效 对象,而不是 相等 对象。
如果您出于任何原因不能使用单独的 Comparator
,您的 Employee
对象将根本不一致,即使您应该得到 "workable" .hashCode()
实施。
我想,你不能在你的情况下写一个一致的 hashCode
,因为你的 equals
违反了 Object.equals
方法的契约,即传递性:
It is transitive: for any non-null reference values
x
,y
, andz
, ifx.equals(y)
returnstrue
andy.equals(z)
returnstrue
, thenx.equals(z)
should returntrue
.
假设你有这个代码:
Employee a = new Employee(1, "John");
Employee b = new Employee(1, "James");
Employee c = new Employee(2, "James");
在这种情况下,您的等于运算 a.equals(b)
和 b.equals(c)
,而不是 a.equals(c)
。
我建议重新考虑 equals
的实施。可能您的 Employee
定义了 eId
或 eName
,因此最好添加一个 boolean
字段来说明是 eId
还是 eName
应该使用。这样你就可以轻松实现equals
和hashCode
。这样的实现可能是这样的(为简单起见,假设 eName
不能是 null
):
class Employee {
boolean useName;
int eId = 0;
String eName;
Employee(int id) {
this.eId = id;
this.useName = false;
}
Employee(String name) {
this.eName = name;
this.useName = true;
}
@Override
public int hashCode() {
return useName ? eName.length() * 1337 : eId * 7331;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (useName != other.useName)
return false;
if (useName) {
if (eName.length() != other.eName.length())
return false;
} else {
if (eId != other.eId)
return false;
}
return true;
}
}