在Java中为具有循环引用的对象实现equals和hashCode [英] Implementing equals and hashCode for objects with circular references in Java
问题描述
我定义了两个类,它们都包含对另一个对象的引用。它们看起来与此类似(这是简化的;在我的真实域模型中,A类包含B的列表,每个B都有一个返回到父A的引用):
I have two classes defined such that they both contain references to the other object. They look similar to this (this is simplified; in my real domain model class A contains a list of B and each B has a reference back to parent A):
public class A {
public B b;
public String bKey;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((b == null) ? 0 : b.hashCode());
result = prime * result + ((bKey == null) ? 0 : bKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof A))
return false;
A other = (A) obj;
if (b == null) {
if (other.b != null)
return false;
} else if (!b.equals(other.b))
return false;
if (bKey == null) {
if (other.bKey != null)
return false;
} else if (!bKey.equals(other.bKey))
return false;
return true;
}
}
public class B {
public A a;
public String aKey;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((a == null) ? 0 : a.hashCode());
result = prime * result + ((aKey == null) ? 0 : aKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof B))
return false;
B other = (B) obj;
if (a == null) {
if (other.a != null)
return false;
} else if (!a.equals(other.a))
return false;
if (aKey == null) {
if (other.aKey != null)
return false;
} else if (!aKey.equals(other.aKey))
return false;
return true;
}
}
hashCode $ Eclipse使用A和B的两个字段生成了c $ c>和
equals
。问题是调用等于$ c两个对象上的$ c>或
hashCode
方法导致 StackOverflowError
,因为它们都调用另一个对象的等于
和 hashCode
方法。例如,以下程序将使用上述对象以 StackOverflowError
失败:
The hashCode
and equals
have been generated by Eclipse using both fields of both A and B. The problem is that calling the equals
or hashCode
method on either object results in a StackOverflowError
since they both call the other object's equals
and hashCode
method. For example the following program will fail with StackOverflowError
using the above objects:
public static void main(String[] args) {
A a = new A();
B b = new B();
a.b = b;
b.a = a;
A a1 = new A();
B b1 = new B();
a1.b = b1;
b1.a = a1;
System.out.println(a.equals(a1));
}
如果在使用循环关系定义域模型时存在固有错误这样请告诉我。虽然我知道这是一个相当普遍的情况,但是对吗?
If there is something inherently wrong with having a domain model defined with circular relationships in this way then please let me know. As far as I can tell though this is a fairly common scenario, correct?
定义 hashCode
和等于
?我想保留 equals
方法中的所有字段,以便它是对象的真正深度相等比较,但我不知道如何解决这个问题。谢谢!
What is best practice for defining hashCode
and equals
in this case? I want to keep all fields in the equals
method so that it is a true deep equality comparison on the object but I don't see how I can with this problem. Thanks!
推荐答案
我同意I82的评论,你应该避免B引用他们的父母:这是信息重复,通常是只会导致麻烦,但您可能需要这样做。
I agree with the comment of I82Much that you should avoid having B referencing their parent: it's information duplication, which usually only leads to trouble, but you might need to do so in your case.
即使您将父参考留在 B
,就哈希码而言,你应该完全忽略父引用,只使用 B
的 true 内部变量来构建哈希码。
Even if you leave the parent reference in B
, as far as hash codes are concerned you should completely ignore the parent reference and only use the true inner variables of B
to build the hash code.
A
只是容器,它们的值完全由它们的内容决定,这是它们的值。包含 B
s,他们的哈希键也应如此。
The A
s are just containers and their value is fully determined by their content, which is the values of the contained B
s, and so should their hash keys.
如果 A
是一个无序集合,你必须非常小心你从 B
值构建的哈希码(或 B
哈希码)不依赖于某些排序。例如,如果通过在某个序列中添加和乘以包含的 B
的哈希码来构建哈希码,则应首先通过增加顺序来排序哈希码计算和/乘的结果。同样, A.equals(o)
不得依赖于 B
的排序(如果是无序集)。
If A
is an unordered set, you must be very careful that the hash code you are building from the B
values (or B
hash codes) is not dependent on some ordering. For example, if the hash code is build by adding and multiplying the hash codes of the contained B
's in some sequence, you should first order the hash codes by increasing order before computing the result of the sums/multiplications. Similarly, A.equals(o)
must not depend on the ordering of the B
s (if unordered set).
请注意,如果您在 A A 中使用
java.util.Collection
code>,然后通过忽略父引用来修复 B
的哈希代码将自动给出有效的 A
哈希码,因为集合
默认情况下具有良好的哈希码(订购或不订购)。
Note that if you are using a java.util.Collection
within A
, then just fixing the B
s hash code by ignoring the parent reference will automatically give valid A
hash codes since the Collection
s have good hash codes by default (ordering or not).
这篇关于在Java中为具有循环引用的对象实现equals和hashCode的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!