![](/img/trans.png)
[英]Java overriding equals() and hashcode() for two interchangeable integers
[英]Maintaining hashCode contract for the specific condition, equals() depending on two integers
我有一个基本的结构类:
class Employee {
int eId;
String eName;
Employee(int id, String name) {
this.eId= id;
this.eName= name;
}
如果满足以下任何条件,则equals()
应返回true:
eId
是一样的。 eName
是一样的。 eName
长度相同。 我在覆盖equals()
没有问题,但是,为了维护哈希代码契约,我也应该覆盖hashCode()
。 因此,hashCode应该依赖于eId
和eName.length()
(如果eName
s相等,它们的长度也将相等)。 所以有四种情况:
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()
应返回e1
, e2
和e3
的相同值以及e4
的不同值。 我无法想出满足这一要求的逻辑。
这是确切的问题:
创建一个类(具有参数名称,id等)。 显示如果将比较此类的2个对象,则它们应在以下任何一种情况下返回true:
A.两者的ID相同。
B.两者的名称相同。
C.两者名称的长度相同。
确保不违反HashCode合同。
你遇到了麻烦,因为你的平等概念是不一致的。 具体来说,它不是传递性的,它是.equals()
的合同所要求的。
它是传递性的 :对于任何非空引用值
x
,y
和z
,如果x.equals(y)
返回true
而y.equals(z)
返回true
,则x.equals(z)
应返回true
。
根据您的定义, e1
等于e2
和e3
,但e2
不等于e3
。 这与Java的平等概念不相容。 这也是您在定义合理的.hashCode()
实现时遇到麻烦的原因。
但是,您可以做的是定义自定义Comparator
(或者如果您使用的是Guava,则Ordering
)。 对于大多数用例(如排序,搜索或过滤),您应该能够像使用.equals()
方法一样使用单独的Comparator
实例。 您正在有效地尝试定义等效对象,而不是相等对象。
如果由于某种原因无法使用单独的Comparator
,那么您的Employee
对象将基本上不一致,即使您应该实现“可行”的.hashCode()
,也会出现问题。
我想,你不能在你的情况下编写一致的hashCode
,因为你的equals
打破了Object.equals
方法的契约,即transitivity:
它是传递性的 :对于任何非空引用值
x
,y
和z
,如果x.equals(y)
返回true
而y.equals(z)
返回true
,则x.equals(z)
应返回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;
}
}
如果您使用Java 7,那么我认为使用java.util.Objects很容易:
@Override
public int hashCode() {
return Objects.hash(eld,eName.length());
}
或者您可以考虑使用Guava ,它在com.google.common.base.Objects
下具有相同的方法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.