2012-03-07 19 views
3

ジェネリックに関する質問があります。 私は、次のインターフェイスがあります。コールb.setA(this)がオフであることを、私にはその明確な一般的な2種類のバインド

public abstract class AImplOne<B extends InterfaceA.InterfaceB> implements InterfaceA<B> { 

    private final B b; 

    public AImplOne(B b) { 
     this.b = b; 
     b.setA(this); // <-- Unchecked call... 
    } 
} 

- しかし、私は、それを好きではない:

public interface InterfaceA<B extends InterfaceA.InterfaceB> { 

    public interface InterfaceB<A extends InterfaceA> { 

     void setA(A a); 
    } 
} 

そしてInterfaceA次の抽象実装を呼び出している、私にはその明確な、

public abstract class AImplTwo<A extends InterfaceA, B extends InterfaceA.InterfaceB<A>> implements InterfaceA<B> { 

    private final B b; 

    public AImplTwo(B b) { 
     this.b = b; 
     b.setA((A)this); // <-- Unchecked cast 
    } 
} 

そして再び:私は、第二の抽象実装を試してみました0はチェックされていないキャストです。

しかし、チェックされていないコードを取り除くには、これを実装または再設計する必要がありますか?

+5

ジェネリックに関する質問で1文字のクラス名「A」を使用すると、非常に混乱します – artbristol

+0

ネストされたクラスを使用するだけでなく、AImplはAImplOneまたはAImplTwoでなければなりません。質問名にはタイプミスがあります'B *>'の型パラメータがありません。問題があるかもしれませんが、サンプルコードが少し複雑すぎます。 – rlegendi

+0

@artbristol:Good Point: 「InterfaceA」に「A」、「InterfaceB」に「B」を変更しました – Peter

答えて

2

あなたが実際にあなたが生の型を使用することにより破る相互再帰的な一般的な定義を持っている:

b.setA((A)this); // <- Unchecked cast 

thisには、タイプInterfaceA<? extends InterfaceA.InterfaceB<? extends InterfaceA>>のですが、それはタイプInterfaceA<? extends InterfaceA.InterfaceB<? extends InterfaceA<? extends InterfaceA.InterfaceB<...>>>>でなければなりません。代わりに

public interface InterfaceA<B extends InterfaceA.InterfaceB<?>> { 

    public interface InterfaceB<A extends InterfaceA<B>> { //<- cannot make a static reference to the non-static type B 

     void setA(A a); 
    } 
} 

を使用する必要がありますが、あなたは(インターフェイス宣言は常に静的です)静的インタフェース宣言で、非静的である、Bを使用することはできません。

詳細については

、一つのさらなる挑戦:今interface InterfaceB<A extends InterfaceA<? extends InterfaceA.InterfaceB<?>>>InterfaceAのネストされた型パラメータは再びInterfaceA.InterfaceB<?>の任意のサブクラスであるため、

代替

public interface InterfaceA<B extends InterfaceA.InterfaceB<?>> { 

    public interface InterfaceB<A extends InterfaceA<? extends InterfaceA.InterfaceB<?>>> { 

     void setA(A a); 
    } 
} 


abstract class AImplTwo<B extends InterfaceA.InterfaceB<A>, A extends InterfaceA<B>> implements InterfaceA<B> { 

    private final B b; 

    public AImplTwo(B b) { 
     this.b = b; 
     b.setA((A)this); // <-- Unchecked cast 
    } 
} 
を使用するには、再度、未チェックのキャストが発生します。


更新、あなたは一般的な設計のために求めてきましたので、:

私は具体的な実装から抽象化としてInterfaceB(一般的には実際には、インタフェース)を思うだろう:あなただけのインターフェイスInterfaceBを必要とし、 InterfaceAの実装では実装の詳細ではありません。 InterfaceBは契約のようなものであり、実装については気にしません。したがってInterfaceBの実装にInterfaceAの実装を結合するための必要はありません。

public interface InterfaceA { 

    public interface InterfaceB { 

     void setA(InterfaceA a); 
    } 
} 

私が見ることができない理由のために、あなたはそのInterfaceBのすべてのインスタンスに対して同じ型を持つようにしたいんのみ、場合ジェネリックが必要です。逆もまた同様です。上記の最後のジェネリックの例では、少なくともInterfaceAとInterfaceBの型を修正することができ、AのBとBのAが同じであることを動的に宣言するだけで済みます。全くタイプがチェックソリューションは、Javaに存在しないことを示す

は難しいですが、多分それはJavaが延びており、スーパーの組み合わせを許可されている場合は解決策になる次の例でもっともらしくなった:

public interface A<TB extends A.B<?>> { 

    public interface B<TA extends A<? extends A.B<?>>> { 

     void setA(TA a); 
    } 
} 


class AImplTwo<TB extends A.B<TA>, TA extends AImplTwo<TB, TA> super AImplTwo<TB, TA>> implements A<TB> { 

    private final TB b; 

    public AImplTwo(TB b) { 
     this.b = b; 
     b.setA((TA)this); 
    } 
} 

.. 。それを考えようとすると、プラグイン可能なタイプのシステムはJavaにさらにタイピングを追加し、この拡張とスーパーの組み合わせを可能にし、したがってあなたの問題に対する解決策を提供するかもしれません。しかし、私はそれがあなたが得るもののためにはあまりにも複雑であることを知り、ジェネリックスなしでインターフェイスを使用するか、チェックされていないキャストを使用するだけです。

+0

これは生のタイプを使用してのみ行うことができますが、これをよりエレガントに解決するにはどうすればよいですか?実装は抽象サブクラスでお互いを知っていますか? – Peter

+0

@Peter:私の更新を見てください。 – DaveFar

関連する問題