3

2 つの異なるデータベース エンティティを表す 2 つのクラスがあります。それらの関係は 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 をどのように実装すればよいでしょうか?

4

4 に答える 4

4

現在のように、企業のアイデンティティは従業員によってのみ定義されます。同様に、従業員の ID は、その会社によってのみ定義されます。それが相互の論理的依存関係にどのようにつながるか分かりますか?

コードでその論理的な依存関係を壊す必要があります。会社と従業員を論理的に一意に識別するにはどうすればよいでしょうか? 通常、名前 (文字列)、数値 (int/long)、または同様のプリミティブ フィールドの組み合わせなど、何らかの意味のある一意の識別子を使用してこれを行います。

于 2012-03-29T03:39:51.683 に答える
2

2つのバージョンが利用可能です。会社は従業員を保管する「主要な」クラスであるべきだと思います。

  1. バージョン: 従業員の equals で、「==」を使用して、会社のオブジェクトが等しいかどうかを確認します (あまり良くありません)。
  2. バージョン: 会社に一意の ID を割り当て、従業員の会社 ID のみが等しいことを比較します

h番目

于 2012-03-29T03:40:10.397 に答える
1

Company.equals メソッド内で従業員のリストを比較しないでください。名前のように、意味があり、等号内で比較を実行するために使用できる会社の他の属性はありますか? または株式記号?

于 2012-03-29T03:41:42.337 に答える
1

Companyと の間に再帰的な依存関係を誤って設定しましたEmployee。メソッドは、すべての従業員のCompany#hashCode()個々のハッシュコードを計算する必要があり、Employee#hashCode()メソッドは会社のハッシュコードに依存するため、無限再帰につながります。

会社オブジェクトのハッシュコードは、その中の従業員に依存してはなりません。ハッシュ コードはある意味でオブジェクトの「アイデンティティ」であり、新しい従業員が追加されたときに変更されるべきではありません。社員も同じ。従業員が別の会社に移動したからといって、従業員のアイデンティティを変更するべきではありません。

これらのメソッドは、意味のある ID 属性に関して再定義する必要があります。コードには表示されませんが、 と の両方CompanyEmployee名前などの他のメンバー変数が必要です。その属性に基づいて hashCode と equals の実装を行います。

于 2012-03-29T03:45:20.020 に答える