【发布时间】:2012-02-10 09:47:59
【问题描述】:
我定义了两个类,它们都包含对另一个对象的引用。它们看起来与此类似(这是简化的;在我的真实域模型中,A 包含一个 B 列表,每个 B 都有一个对父 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 和 equals 是由 Eclipse 使用 A 和 B 的两个字段生成的。问题是在任一对象上调用 equals 或 hashCode 方法都会导致 StackOverflowError,因为它们都调用另一个对象的equals 和hashCode 方法。例如,使用上述对象,以下程序将失败并显示StackOverflowError:
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));
}
如果以这种方式使用循环关系定义域模型存在固有问题,请告诉我。据我所知,虽然这是一种相当常见的情况,对吗?
在这种情况下,定义 hashCode 和 equals 的最佳做法是什么?我想将所有字段保留在 equals 方法中,以便对对象进行真正的深度相等比较,但我不知道如何解决这个问题。谢谢!
【问题讨论】:
-
为什么需要子项对父项有引用?在序列化方面,这会让你的生活变得非常复杂
-
我正在使用遗留域模型。我的序列化基本上忽略了孩子的父关系,然后修复了反序列化的关系。在域模型中循环引用不是很常见吗?底层数据库关系是 OneToMany,它被 JBoss 工具逆向工程为带有循环引用的 JPA 对象。