我有一个基本类,结构如下:
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:
一个。两者的ID都相同。
B中。两者的名称相同。
℃。两者的名称长度相同。
确保不违反HashCode合同。
答案 0 :(得分:7)
你遇到了麻烦,因为你的平等概念是不一致的。具体来说,它不是传递性的,.equals()
的合同要求。
transitive :对于任何非空引用值
x
,y
和z
,如果x.equals(y)
返回{{1} }和true
返回y.equals(z)
,然后true
应该返回x.equals(z)
。
根据您的定义,true
等于e1
和e2
,但e3
不等于e2
。这与Java的平等概念不相容。这也是您在定义合理e3
实施时遇到麻烦的原因。
但是,您可以做的是定义自定义Comparator
(或Ordering
,如果您使用的是Guava)。对于大多数用例(如排序,搜索或过滤),您应该能够使用单独的.hashCode()
实例,就像使用Comparator
方法一样。您实际上是在尝试定义等效的对象,而不是相等的对象。
如果由于某种原因无法使用单独的.equals()
,那么Comparator
对象将从根本上不一致,即使您应该获得“可行”Employee
,也会出现问题实现。
答案 1 :(得分:4)
我想,你不能在你的案例中写出一致的DataContext
,因为你的hashCode
违反了Object.equals
方法的合同,即及物性:
transitive :对于任何非空引用值
equals
,x
和y
,如果z
返回{{1} }和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
答案 2 :(得分:0)
如果您使用Java 7,那么我认为使用java.util.Objects很容易:
@Override
public int hashCode() {
return Objects.hash(eld,eName.length());
}
或者你可以考虑Guava,它在com.google.common.base.Objects