1

Collections の SortedSet (この場合は Set 自体ですが、必ずしも一般的ではありません) が必要です。これは Collection のサイズで並べ替えられます。これは、Comparator を equals() と一致させるという禁止事項に違反しているようです。つまり、2 つのコレクションは (異なる要素を持つことによって) 等しくなくても、同じ値と比較できます (同じ数の要素を持つため)。

概念的には、等しいサイズのセットを並べ替える方法を Comparator に入れることもできますが、並べ替えを使用してもそれを利用できず、同じサイズのコレクションを比較するための便利で直感的な方法は実際にはありません (少なくとも、私の特定のケースでは)、それは無駄のように思えます。

この矛盾のケースは問題のように見えますか?

4

5 に答える 5

8

SortedSetインターフェイスはコアSetを拡張するため、仕様で概説されている契約に準拠する必要がありSetます。

これを実現する唯一の方法は、要素のequal()メソッドの動作を自分のものと一致させることです。Comparatorその理由は、コアSetが等価に基づいてSortedSet動作するのに対し、比較に基づいて動作するためです。

たとえば、コア Set インターフェイスで定義されたメソッドは、この新しい要素を引数としてメソッドが true を返すadd()要素が既に存在する場合、セットに要素を追加できないことを指定します。equal()まあ、SortedSet使わないequal()で、使うcompareTo()。したがって、あなたcompareTo()が返す場合、たとえreturnであっfalseても要素が追加されるため、契約が破られます。equals()trueSet

ただし、これ自体は実用的な問題ではありませんvsがそうでなくSortedSetても、動作は常に一貫しています。compare()equals()

于 2009-10-02T16:50:58.863 に答える
4

ChssPly76 がコメントに書いたように、2 つの Collection のサイズが同じで等しくない場合は、hashCode を使用して compareTo 呼び出しを決定できます。これは、同じサイズの 2 つのコレクションがあり、等しくなくても同じ hashCode を持つまれなケースを除いて、正常に機能します。確かに、その可能性はかなり低いですが、考えられることです。本当に注意したい場合は、hashCode の代わりに System.identityHashCode を使用してください。これにより、コレクションごとに一意の番号が付与され、衝突が発生することはありません。

結局のところ、これにより、サイズが一致する 2 つのコレクションの場合に任意の順序で、セット内のコレクションをサイズで並べ替える機能が提供されます。これだけあれば、通常の比較よりも遅くはありません。異なる JVM インスタンス間で順序を一致させる必要がある場合、これは機能せず、別の方法で行う必要があります。

疑似コード:

if (a.equals(b)) {
    return 0;
} else if (a.size() > b.size()) {
    return 1;
} else if (b.size() > a.size()) {
    return -1;
} else {
    return System.identityHashCode(a) > System.identityHashCode(b) ? 1 : -1;
}
于 2009-10-02T21:24:02.900 に答える
3

これは、Comparator を equals() と一致させるという禁止事項に違反しているようです。つまり、2 つのコレクションは (要素が異なるため) 等しくなくても、同じ値と比較できます (要素の数が同じため)。

Comparator(Javadoc で) 明言されていようと暗示されていようと、 がオブジェクトの の実装と一致しているという要件はありませんboolean equals(Object)

ComparableComparatorは、異なる目的を持つ 別個のインターフェイスであることに注意してください。Comparableクラスの「自然な」順序を定義するために使用されます。equalsその文脈では、とcompateToが矛盾していることは悪い考えです。対照的にComparator、クラスの自然な順序とは異なる順序を使用する場合は、a を使用します。

編集: これは、SortedSet の Javadoc からの完全な段落です。

ソートされたセットが Set インタフェースを正しく実装するためには、(明示的なコンパレータが提供されているかどうかに関係なく) ソートされたセットによって維持される順序付けが equals と一致している必要があることに注意してください。これは、Set インターフェースが equals 操作に関して定義されているためですが、ソートされたセットはその compareTo (または比較) メソッドを使用してすべての要素の比較を実行するためです。であるため、このメソッドで等しいと見なされる 2 つの要素は、並べ替えられたセットの観点からは等しいです。並べ替えられたセットの動作は、その順序付けが equals と一致しない場合でも明確に定義されています。Set インターフェースの一般的な契約に従わないだけです。

最後の文を強調しました。要点は、そのような SortedSet はおそらく期待どおりに機能しますが、一部の操作の動作は仕様と完全に一致しないSetということです...仕様ではequalsメソッドの観点から動作が定義されているためです。

したがって、実際に、一貫性の要件が明記されています (私の間違いです) が、それを無視した場合の結果は、あなたが考えるほど悪くはありません。もちろん、それを行うかどうかはあなた次第です。私の推定では、コードを徹底的にコメントし、SortedSet が「リーク」しないことを確認すれば、問題ないはずです。

ただし、コレクションの「サイズ」のみを確認するコレクションの Comparator が機能するかどうかはわかりません...セマンティックな観点から。つまり、(たとえば) 2 つの要素を持つすべてのコレクションが等しいと本当に言いたいのでしょうか? これは、セットに特定のサイズのコレクションを 1 つしか含めることができないことを意味します...

于 2009-10-03T02:05:06.653 に答える
1

Comparatoraが と同じ結果を返さなければならない理由はありませんequals()。実際、ComparatorAPI が導入されたのは、equals()それだけでは十分ではないためです。コレクションを並べ替えたい場合は、2 つの要素が小さいか大きいかを知る必要があります。

于 2009-10-02T16:15:50.137 に答える
0

標準APIの一部としてのSortedSetが、Setインターフェースで定義されたコントラクトを破り、equalsメソッドの代わりにComparatorを使用して等式を定義するのは少し奇妙ですが、そのようになっています。

実際の問題が、含まれているコレクションのサイズに従ってコレクションのコレクションを並べ替えることである場合は、Collections.sort(List、Comparator>);を使用して並べ替えることができるリストを使用することをお勧めします。

于 2009-10-02T17:10:08.033 に答える