web-dev-qa-db-ja.com

Java:なぜコレクションがコンパレータを受け入れるのに(仮説的な)HasherとEquatorを受け入れないのですか?

この問題は、インターフェイスの実装が異なる場合に最も明確になり、特定のコレクションの目的では、オブジェクトのインターフェイスレベルのビューのみに関心があります。たとえば、次のようなインターフェースがあるとします。

_public interface Person {
    int getId();
}
_

クラスの実装でhashcode()およびequals()を実装する通常の方法では、equalsメソッドに次のようなコードが含まれます。

_if (getClass() != other.getClass()) {
    return false;
}
_

これにより、Personの実装をHashMapに混在させると問題が発生します。 HashMapPersonのインターフェースレベルのビューのみを考慮する場合、実装クラスのみが異なる重複が発生する可能性があります。

すべての実装に同じリベラルequals()メソッドを使用してこのケースを機能させることはできますが、equals()が異なるコンテキストで間違った動作をするリスクがあります(比較など) 2つのPersons(バージョン番号付きのデータベースレコードによってサポートされます)。

私の直感は、平等はクラスごとではなくコレクションごとに定義する必要があることを教えてくれます。順序に依存するコレクションを使用する場合は、カスタムComparatorを使用して、各コンテキストで正しい順序を選択できます。ハッシュベースのコレクションには類似物はありません。どうしてこれなの?

明確にするために、この質問は「 。equals()がJavaのクラスにあるのに、なぜインターフェースの.compareTo()なのか 」とは異なります。これは、コレクションの実装を扱うためです。 compareTo()equals()/hashcode()はどちらも、コレクションを使用するときの普遍性の問題に悩まされています。異なるコレクションに対して異なる比較関数を選択することはできません。したがって、この質問では、オブジェクトの継承階層はまったく問題ではありません。重要なのは、比較関数がオブジェクトごとに定義されるか、コレクションごとに定義されるかです。

25
Sam

このデザインは「ユニバーサルエクイティ」として知られています。2つのものが等しいかどうかは、ユニバーサルプロパティであると考えられています。

さらに、等価性はtwoオブジェクトのプロパティですが、オブジェクト指向では、常に1つの単一オブジェクトに対してメソッドを呼び出し、そのオブジェクトはそれを処理する方法のみを決定しますメソッド呼び出し。したがって、Javaのような設計では、等価性は比較される2つのオブジェクトの1つのプロパティであり、対称性などのいくつかの基本的な等価性プロパティを保証することもできません(a == bb == a )、最初のケースではメソッドはaで呼び出され、2番目のケースではbで呼び出されます。OOの基本原則により、それはaの決定(最初のケース)またはbの決定(2番目のケース)は、それ自体が他の1つと等しいかどうかを判断します。対称性を得る唯一の方法は、2つのオブジェクトを連携させることですが、そうでない場合は…頑張ってください。

1つの解決策は、1つのオブジェクトのプロパティではなく、2つのオブジェクトのプロパティまたは3番目のオブジェクトのプロパティを等しくすることです。後者のオプションは、普遍的な同等性の問題も解決します。同等性を3番目の「コンテキスト」オブジェクトのプロパティにすると、コンテキストごとに異なるEqualityComparerオブジェクトを持つことが想像できるためです。

これはis Haskell用に選択されたデザインで、たとえばEqタイプクラスを使用しています。これは、一部のサードパーティScalaライブラリ(ScalaZなど))によって選択された設計でもありますが、ユニバーサルを使用するScalaコアまたは標準ライブラリではありません。基盤となるホストプラットフォームとの互換性のための同等性。

興味深いことに、JavaのComparable/Comparatorインターフェースで選択された設計でもあります。 Java=の設計者は明らかに問題を認識していましたが、何らかの理由で順序付けのためにのみ解決しましたが、等価性(またはハッシュ化)については解決しませんでした。

だから、質問について

なぜComparatorインターフェイスがあるのにHasherEquatorがないのですか?

答えは「わからない」です。明らかに、Javaの設計者はComparatorの存在から明らかなように、この問題に気づいていましたが、明らかに等価性とハッシュの問題だとは考えていませんでした。その他言語とライブラリは異なる選択をします。

23
Jörg W Mittag