在Java中的交叉引用类上重写equals/hashCode会导致StackOverflowerError
我有两个类,它们代表两个不同的数据库实体。它们的关系在db中为1:m,在类结构中表示如下:在Java中的交叉引用类上重写equals/hashCode会导致StackOverflowerError,java,equals,stack-overflow,cross-reference,Java,Equals,Stack Overflow,Cross Reference,我有两个类,它们代表两个不同的数据库实体。它们的关系在db中为1:m,在类结构中表示如下: public class Company { private List<Employee> employees; public List<Employee> getEmployees() { return employees; } public void setEmployees(List<Employee> emp
public class Company {
private List<Employee> employees;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
public class Employee {
private Company company;
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
我希望它能通过,因为1号公司和2号公司都有相同的员工名单,但StackOverflower失败了:
java.lang.StackOverflowError
at java.util.AbstractList$Itr.<init>(AbstractList.java:318)
at java.util.AbstractList$Itr.<init>(AbstractList.java:318)
at java.util.AbstractList$ListItr.<init>(AbstractList.java:377)
at java.util.AbstractList.listIterator(AbstractList.java:315)
at java.util.AbstractList.listIterator(AbstractList.java:284)
at java.util.AbstractList.equals(AbstractList.java:502)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
at java.util.AbstractList.equals(AbstractList.java:507)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
at java.util.AbstractList.equals(AbstractList.java:507)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
...
java.lang.StackOverflower错误
位于java.util.AbstractList$Itr。(AbstractList.java:318)
位于java.util.AbstractList$Itr。(AbstractList.java:318)
位于java.util.AbstractList$ListItr。(AbstractList.java:377)
位于java.util.AbstractList.listIterator(AbstractList.java:315)
位于java.util.AbstractList.listIterator(AbstractList.java:284)
位于java.util.AbstractList.equals(AbstractList.java:502)
位于com.test.Company.equals(Company.java:37)
位于com.test.Employee.equals(Employee.java:35)
位于java.util.AbstractList.equals(AbstractList.java:507)
位于com.test.Company.equals(Company.java:37)
位于com.test.Employee.equals(Employee.java:35)
位于java.util.AbstractList.equals(AbstractList.java:507)
位于com.test.Company.equals(Company.java:37)
位于com.test.Employee.equals(Employee.java:35)
...
我知道失败的原因是类中的交叉引用,因此是equals/hashCode方法。但是我应该如何实现equals/hashCode来避免无限递归呢?现在,公司的身份完全由员工定义。同样,员工的身份仅由其公司定义。你看到这是如何导致相互逻辑依赖的吗
您需要在代码中打破这种逻辑依赖关系。您如何在逻辑上唯一地识别公司和员工?通常,您可以使用某种有意义的唯一标识符来完成此操作:名称(字符串)、数字(int/long)或一些类似的基本字段组合。Imho有两种版本可用。我认为公司应该是“领导”阶层,存储员工
hth不要比较公司内的员工名单。equals方法。公司是否还有其他有意义的属性,可以用来在equals中进行比较,比如名称?还是股票符号?您无意中在
公司
和员工
之间建立了递归依赖关系。Company#hashCode()
方法需要计算每个员工的个人hashCode,Employee#hashCode()
方法依赖于公司的hashCode,导致无限递归
公司对象的哈希代码不应依赖于其中的员工。从某种意义上说,哈希代码是对象的“标识”,当向其添加新员工时,该标识不应更改。员工也一样。员工的身份不应该仅仅因为他/她搬到另一家公司而改变
您必须根据一些有意义的标识属性重新定义这些方法。您的代码没有显示它,但是
公司
和员工
必须有一些其他成员变量,例如名称。基于该属性的hashCode和equals实现。谢谢,MΓΓББLL。这些类上还有其他字段(简单字符串,如公司名称、员工姓名等),它们包含在equals/hashCode方法中。我只是在问题中省略了它们,因为它们不会引起任何问题,交叉引用是导致问题的原因。在这种情况下,听起来你应该从company\hashCode()
和company\equals()
方法中省略公司的员工。员工可以由其工作的公司定义,但公司不是由其员工定义的(无论如何,是唯一的)。正如我对schtever的回答所评论的,这将导致两个同名但不同员工的公司相等,这是不对的。那么员工不应该由其工作的公司唯一定义!就像我说的,你必须选择在哪里打破逻辑循环。由您来决定是什么唯一地定义了您的实体。如果名称不足以唯一指定公司,则可以为公司引入单独/独立的标识符字段。你不能两全其美:你需要选择从某个地方开始。谢谢你,MΓΓБСLL。我没有想到单个(或复合)标识符会表示相同类型的两个对象相等。出于某种原因,我认为我需要使用类中的所有字段。也许Eclipse自动生成这些方法需要更加灵活。谢谢你的评论。这些类上还有其他简单的字段。你的建议会导致两个同名但不同员工的公司平等,这是不对的。你能详细解释一下为什么这是不对的吗?您是否会遇到两个同名公司实际上是不同实体的情况?谢谢,schtever。正如我在接受的答案中所评论的那样,我没有想到单个(或复合)标识符会表示相同类型的两个对象相等。出于某种原因,我认为我需要使用该类中的所有字段。我希望拥有相同员工名单的两家公司被视为平等的。仅仅比较身份属性是怎么可能的。不要使用equals
,为此编写一个单独的比较器。谢谢,phloc。我选择选项2。
public class EqualsTest {
@Test
public void testEquals() {
Company company1 = new Company();
Employee employee1 = new Employee();
employee1.setCompany(company1);
company1.setEmployees(Arrays.asList(employee1));
Company company2 = new Company();
Employee employee2 = new Employee();
employee2.setCompany(company2);
company2.setEmployees(Arrays.asList(employee2));
assertThat(company1, is(company2));
}
}
java.lang.StackOverflowError
at java.util.AbstractList$Itr.<init>(AbstractList.java:318)
at java.util.AbstractList$Itr.<init>(AbstractList.java:318)
at java.util.AbstractList$ListItr.<init>(AbstractList.java:377)
at java.util.AbstractList.listIterator(AbstractList.java:315)
at java.util.AbstractList.listIterator(AbstractList.java:284)
at java.util.AbstractList.equals(AbstractList.java:502)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
at java.util.AbstractList.equals(AbstractList.java:507)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
at java.util.AbstractList.equals(AbstractList.java:507)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
...