簡體   English   中英

在Java中交叉引用類上覆蓋equals / hashCode會導致StackOverflowError

[英]Overriding equals/hashCode on cross referencing classes in Java causes StackOverflowError

我有兩個代表兩個不同數據庫實體的類。 他們在db中的關系為1:m,它在類結構中表示如下:

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;
    }

}

現在我想在這些類上重寫equals / hashCode。 Eclipse為我生成以下代碼:

public class Company {

    private List<Employee> employees;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((employees == null) ? 0 : employees.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Company other = (Company) obj;
        if (employees == null) {
            if (other.employees != null)
                return false;
        } else if (!employees.equals(other.employees))
            return false;
        return true;
    }

}

public class Employee {

    private Company company;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((company == null) ? 0 : company.hashCode());
        return result;
    }

    @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 (company == null) {
            if (other.company != null)
                return false;
        } else if (!company.equals(other.company))
            return false;
        return true;
    }

}

如果我運行以下測試:

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));
    }

}

我希望它能夠通過,因為company1和company2都有相同的員工列表,但是它因StackOverflowError而失敗:

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)
        ...

我知道這種失敗的原因是類中的交叉引用,因此是equals / hashCode方法。 但是我應該如何實現equals / hashCode以避免不定式遞歸?

就像現在一樣,公司的身份完全由其員工定義。 同樣,員工的身份僅由其公司定義。 你知道這是如何導致相互邏輯依賴的嗎?

您需要在代碼中打破邏輯依賴性。 您如何在邏輯上唯一地識別公司和員工? 通常,您可以使用某種有意義的唯一標識符來執行此操作:名稱(字符串),數字(int / long)或某些類似的基本字段組合。

Imho有2個版本可供選擇。 我認為公司應該是“領先”類,存儲員工。

  1. version:在員工equals中,使用“==”檢查公司的對象是否相等(不是很好)
  2. version:為您的公司分配一個唯一的ID,並僅比較員工中的公司ID等於

心連心

不要比較Company.equals方法中的員工列表。 公司的其他屬性是否有意義並且可以用於在equals中執行比較,例如名稱? 還是股票代碼?

您無意中在CompanyEmployee之間建立了遞歸依賴關系。 Company#hashCode()方法需要計算每個Employee的各個哈希碼, Employee#hashCode()方法依賴於公司的哈希碼,導致無限遞歸。

公司對象的哈希碼不應該依賴於其中的員工。 哈希代碼在某種意義上是對象的“身份”,在添加新員工時不應該更改。 員工也一樣。 員工的身份不應僅僅因為他/她搬到另一家公司而改變。

您必須根據一些有意義的身份屬性重新定義這些方法。 您的代碼沒有顯示它,但CompanyEmployee必須有一些其他成員變量,例如名稱。 基於該屬性的hashCode和equals實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM