5

がこのメソッドを使用してソートするとしSuperclass implements Comparable<Superclass>ます。これは、 のインスタンスの配列がを使用して同じ方法でソートされることを保証しますか? (compareTo がサブクラス定義でオーバーロードされていないと仮定します)Arrays.sort(ArrayOfSuperInstances);compareTo(Superclass other)Subclass extends SuperclassArrays.sort(ArrayOfSubInstances);

または、言い換えれば、SubclassデフォルトcompareToでそのメソッドを継承するので、スーパークラスのようにソートされることを知ってSuperclassやみくもに使用できますか?Arrays.sort()

4

4 に答える 4

7

はい - それがポリモフィズムの背後にある原理全体であり、具体的にはリスコフ置換原理です。基本的に、A が B のサブクラスである場合、B を使用できる場所ならどこでも A を使用でき、基本的に B の他のインスタンス (または B の他のサブクラス) と同じように動作する必要があります。

ですから、それが起こるだけでなく、ほとんどの場合、あなたが望んでいることです。通常compareTo、サブクラスでは間違っています。

なんで?まあ、Comparable<T>契約の一部は、比較が推移的であるということです。スーパークラスはおそらくそのサブクラスが何をしているかを知らないため、サブクラスがcompareToそのスーパークラスとは異なる答えを与えるような方法でオーバーライドすると、契約が破られます。

たとえば、Square と ColorSquare のようなものがあるとします。Square'scompareToは、2 つの正方形のサイズを比較します。

@Override
public int compareTo(Square other) {
    return this.len - other.len;
}

...一方、ColorSquare は色の比較も追加します (色が Comparable であると仮定しましょう)。Java では ColorSquare を実装することはできませんComparable<ColorSquare>(スーパークラスが既に実装しているためComparable<Square>) が、リフレクションを使用してこれを回避できます。

@Override
public int compareTo(Square other) {
    int cmp = super.compareTo(other);
    // don't do this!
    if (cmp == 0 && (other instanceof ColorSquare)) {
        ColorSquare otherColor = (ColorSquare) other;
        cmp = color.compareTo(otherColor.color);
    }
    return cmp;
}

これは一見無害に見えます。両方の形状が ColorSquare の場合、長さと色が比較されます。それ以外の場合は、長さのみが比較されます。

しかし、次の場合はどうでしょう。

Square a = ...
ColorSquare b = ...
ColorSquare c = ...

assert a.compareTo(b) == 0;  // assume this and the other asserts succeed
assert a.compareTo(c) == 0;
// transitivity implies that b.compareTo(c) is also 0, but maybe
// they have the same lengths but different color!
assert b.compareTo(c) == 1; // contract is broken!
于 2012-08-13T06:05:04.097 に答える
3

デフォルトでは、オーバーライドしていない場合compareTo、そのスーパークラスからの実装が使用されます。


ベスト プラクティスに進み、 TMを開きますEffective Java

の基本的なコントラクトcompareTo(equalsメソッドも同様) は次のとおりです。

  1. Reflexivity :x.compareTo(x)常に 0 にする必要があります。
  2. 対称性:常に反対の符号または 0 を返す必要がありますx.compareTo(y)y.compareTo(x)
  3. 推移性: if x.compareTo(y) > 0and y.compareTo(z) > 0; それからx.compareTo(z) > 0

...オブジェクト指向の抽象化の利点を放棄する意思がない限り、compareTo コントラクトを保持しながらインスタンス化可能なクラスを新しい値コンポーネントで拡張する方法はありません。

更新(おかげでyshavit )

だから、あなたは自分が何を扱っているかを知らなければなりません。理想的には、compareToin サブクラスも記述します。superClass を使用する場合と使用しない場合がありますcompareTo(私が作成した混乱をお詫びします)

compareToサブクラスでまたはを実装すると、対称性または推移equals性のいずれかが破られます。項目 7、有効な Java TMを参照してください。クラスを拡張し、メソッド ( と同じコントラクトを持つ) を別の方法でオーバーライドする方法がないことを示唆しています。equalscompareTo

イコール コントラクトを保持しながら、インスタンス化可能なクラスを拡張してアスペクトを追加する方法はまったくありません。ただし、優れた回避策があります。項目 14「継承より合成を優先する」のアドバイスに従ってください。ColorPoint が Point を拡張する代わりに、ColorPoint にプライベート Point フィールドとパブリック ビュー メソッドを与えます (項目 4)。

于 2012-08-13T05:41:24.670 に答える
0

あなたcompareToがオーバーライドされない限り、またはオーバーライドされたメソッドを呼び出す場合を除き、そうする必要があります。より良い質問は、あなたが試したときに何が起こったのか、そしてあなたの懸念は何かを示すでしょう.

于 2012-08-13T05:40:58.353 に答える
0

はい、compareTo メソッドをオーバーライドしていない場合と同じ動作になりますが、スーパー クラスに実装されている compareTo() メソッドのコードを壊す可能性のある方法で、サブクラスが属性を変更しないようにしてください。

于 2012-08-13T05:42:00.987 に答える