Comparableを実装する抽象クラスを定義しようとしています。次の定義でクラスを定義すると:
_public abstract class MyClass implements Comparable <MyClass>
_
サブクラスはcompareTo(MyClass object)
を実装する必要があります。代わりに、すべてのサブクラスでcompareTo(SubClass object)
を実装し、独自のタイプのオブジェクトを受け入れます。次のような抽象クラスを定義しようとすると:
_public abstract class MyClass implements Comparable <? extends MyClass>
_
「スーパータイプはワイルドカードを指定できない」と文句を言います。
解決策はありますか?
私の意見では少し冗長すぎますが、うまくいきます:
public abstract class MyClass<T extends MyClass<T>> implements Comparable<T> {
}
public class SubClass extends MyClass<SubClass> {
@Override
public int compareTo(SubClass o) {
// TODO Auto-generated method stub
return 0;
}
}
署名を宣言する際に遭遇する機械的な問題は別として、目標はあまり意味がありません。共変比較関数を確立しようとしていますが、これは派生クラスが調整できるインターフェースを確立するという考え全体を打ち破ります。
インスタンスを他のSubClass
インスタンスとのみ比較できるようにサブクラスSubClass
を定義する場合、SubClass
はMyClass
で定義されたコントラクトをどのように満たしますか? MyClass
は、それとそれから派生した型を他のMyClass
インスタンスと比較できると言っていることを思い出してください。 SubClass
に当てはまらないようにしようとしています。つまり、SubClass
はMyClass
の契約を満たしていません。SubClass
の要件は厳しいため、MyClass
をSubClass
に置き換えることはできません。
この問題は、共分散と反分散、およびそれらがどのように型の派生を通じて関数シグネチャを変更できるようにするかを中心にしています。 relax引数の型に対する要件(スーパータイプの署名要求よりも広い型を受け入れる)および strength戻り値の型の要件-スーパータイプの署名よりも狭い型を返すことを約束します。これらの自由のそれぞれは、スーパータイプの派生型の完全な置換を依然として許可します。呼び出し側は、スーパータイプのインターフェースを介して派生型を使用すると違いを知ることができませんが、派生型を具体的に使用する呼び出し元は、これらの自由を利用できます。
Willi's answer は一般的な宣言について何かを教えていますが、セマンティクスを犠牲にしてテクニックを受け入れる前に目標を再検討することをお勧めします。
javaの例を参照してください。
_public abstract class Enum<E extends Enum<E>> implements Comparable<E>
public final int compareTo(E o)
_
sehのコメント:通常、引数は正しいです。しかしジェネリックは型の関係をより複雑にします。ウィリのソリューションでは、サブクラスはMyClassのサブタイプではない可能性があります。
SubClassA
は_MyClass<SubClassA>
_のサブタイプですが、_MyClass<SubClassB>
_のサブタイプではありません
タイプ_MyClass<X>
_は、そのすべてのサブタイプが尊重しなければならないcompareTo(X)
のコントラクトを定義します。そこに問題はありません。
別のソリューションが見つかりました:
ソリューションは次のようになります。
public abstract class MyClass implements ComparableFoo,Comparable<ComparableFoo> {
public int compareTo(ComparableFoo o) {
// your implementation
}
}
このソリューションは、より多くのものがComparableFooを実装する可能性があることを意味します-これは事実ではないかもしれませんが、インターフェイスにコーディングしているので、ジェネリック式は簡単です。
キャプチャが必要かどうかわかりません:
まず、abstractクラスにcompareToを追加します...
public abstract class MyClass implements Comparable <MyClass> {
@Override
public int compareTo(MyClass c) {
...
}
}
次に、実装を追加します...
public class MyClass1 extends MyClass {
...
}
public class MyClass2 extends MyClass {
...
}
Compareを呼び出すと、スーパータイプメソッドが呼び出されます...
MyClass1 c1 = new MyClass1();
MyClass2 c2 = new MyClass2();
c1.compareTo(c2);
public abstract class MyClass<T> implements Comparable<T> {
}
public class SubClass extends MyClass<SubClass> {
@Override
public int compareTo(SubClass o) {
// TODO Auto-generated method stub
return 0;
}
}
「compareTo(SubClassオブジェクト)、独自の型のオブジェクトを受け入れる」と言ったのは知っていますが、抽象クラスを次のように宣言することをお勧めします。
public abstract class MyClass implements Comparable <Object>
mySubClassでcompareToをオーバーライドするときにinstanceofチェックを実行します。
@Override
public int compareTo(Object o) {
if (o instanceof MySubClass)) {
...
}
else throw new IllegalArgumentException(...)
}
「等しい」または「クローン」と同様