12

私が Java の本を読んだとき、著者は、クラスを設計するとき、通常equals()、継承を使用するのは安全ではないと言っていました。例えば:

public final class Date {
    public boolean equals(Object o) {
         // some code here
    }
}

上記のクラスでは、 を配置する必要がfinalあるため、他のクラスはこれを継承できません。そして私の質問は、別のクラスがこれから継承することを許可すると、なぜ安全ではないのですか?

4

2 に答える 2

24

特に対称プロパティを正しくするのは難しい(不可能?)からです。

classVehicleと classがあるとしCar extends Vehicleます。引数も aであり、同じ重みを持つ場合にVehicle.equals()生成されます。実装したい場合は、引数が車でもある場合にのみ生成する必要があり、重量を除いて、メーカー、エンジンなども比較する必要があります。trueVehicleCar.equals()true

次のコードを想像してください。

Vehicle tank = new Vehicle();
Vehicle bus = new Car();
tank.equals(bus);  //can be true
bus.equals(tank);  //false

最初の比較はtrue、偶然にもタンクとバスの重量が同じ場合に結果が出る可能性があります。しかし、タンクは車ではないため、車と比較すると常にfalse.

いくつかの回避策があります。

  • 厳密: 2 つのオブジェクトが等しいのは、それらがまったく同じ型 (およびすべてのプロパティが等しい) である場合に限られます。これは悪いことです。たとえば、サブクラス化して何らかの動作を追加したり、元のクラスを装飾したりする場合です。一部のフレームワークは、気付かないうちにクラスもサブクラス化しています (Hibernate、CGLIB プロキシを使用した Spring AOP...)。

  • Loose: 2 つのオブジェクトは、それらの型が「互換性があり」、内容が (意味的に) 同じである場合、同等です。HashSetたとえば、同じ要素が含まれている場合、2 つのセットは等しいです。一方がそうで、もう一方がそうであるかどうかは問題ではありません(指摘してくれた@veerTreeSetに感謝します)。

    これは誤解を招く可能性があります。2 つLinkedHashSetの s を取ります (コントラクトの一部として挿入順序が重要な場合)。ただし、equals()生のSetコントラクトのみが考慮されるtrueため、明らかに異なるオブジェクトに対しても比較が行われます。

    Set<Integer> s1 = new LinkedHashSet<Integer>(Arrays.asList(1, 2, 3));
    Set<Integer> s2 = new LinkedHashSet<Integer>(Arrays.asList(3, 2, 1));
    System.out.println(s1.equals(s2));
    
于 2012-09-02T20:14:32.557 に答える
11

Martin Odersky (Java のジェネリックと現在の .NET の元のコードベースの背後にいる人物javac) は、彼の著書Programming in Scalaでこの問題に対処する素晴らしい章を持っています。彼は、メソッドを追加することでcanEqual、等価/継承の問題を解決できると提案しています。この議論は、オンラインで入手できる彼の本の初版で読むことができます。

Programming in Scala, First Edition の第 28 章: オブジェクトの等価性

この本はもちろん Scala に言及していますが、同じ考え方が従来の Java にも当てはまります。サンプル ソース コードは、Java のバックグラウンドを持っている人が理解するのにそれほど難しくありません。

編集:

Odersky は 2009 年に Java で同じ概念に関する記事を公開したようで、同じ Web サイトで入手できます。

Java で等価メソッドを記述する方法

この回答で記事を要約しようとしても、それが正義になるとは本当に思いません。等価性の実装でよくある間違いからequals、等価関係としての Java の完全な説明まで、オブジェクトの等価性のトピックを詳細にカバーしています。あなたは本当にそれを読むべきです。

于 2012-09-02T20:24:30.900 に答える