2011-01-07 18 views
0

クラスFoo、クラスAおよびサブクラスBがあるとします。FooはAおよびそのサブクラスをジェネリック型として受け取ります。 AとBの両方とも、そのコンストラクタにFooインスタンスが必要です。 、XはいずれかのAの場合Java:サブクラス化で汎用ワイルドカードを使用する

Foo<X> bar = new Foo<X>; 
new B(bar); 

が可能であるために:私はAさんのFooがタイプAのようにしたい、とBのfooがタイプBまたはSO効果でBのスーパークラスであることが、だから私はこれだけをしたいですB、またはAのサブクラスとB.

のスーパークラスこれまでのところ、これは私が持っているものです両方:

class Foo<? extends A>{ 
    //construct 
} 


class A(Foo<A> bar){ 
    //construct 
} 

class B(Foo<? super B> bar){ 
    super(bar); 
    //construct 
} 

super(...)への呼び出しが動作しない、<A><? super B>よりも厳しいですので。これらの型を強制しながら、コンストラクタを使用する(あるいは別の手段でコードの重複を避ける)ことは、何とかできますか?

編集:Fooはジェネリックパラメータタイプの要素のコレクションを保持し、これらの要素とFooは双方向リンクを持ちます。したがって、AをFooにリンクすることはできません。

+0

実際のコードではありません。 –

+0

はい、単純化したコードです。私は何かを逃したと思いますか? – gibberish

答えて

1

あなたにコンストラクタを変更する場合:

class A(Foo<? extends A> bar){ 
    //construct 
} 

それはあなたがやりたいだろうか?

実際にAのコンストラクタをFooに限定したい場合は、別の保護されたメソッド(別名派生クラスから使用可能)を用意してFooインスタンスを設定する必要があります。このような 何か:

public class A { 

    Foo<?> foo; 

    public A(Foo<A> foo) { 
     setFoo(foo); 
    } 

    protected A() { 
    } 

    protected void setFoo(Foo<?> foo) { 
     this.foo = foo; 
    } 
} 

とB

public class B extends A { 

    public B(Foo<? super B> foo) { 
     setFoo(foo); 
    } 
} 

は今、これは動作します:

new A(new Foo<A>()); 
new A(new Foo<B>()); // this fails compilation 
new B(new Foo<B>()); 

を適切にあなたがAを作成する必要があるかもしれません入力するためのAでfoo要素ためにはパラメータ化されたクラスもあります。

+0

ええ、その可能性を避ける方法がないように思われる – gibberish

+0

hehe :)私はもっと良い変種で答えを更新しました。 –

+0

それはかなり良い解決策、感謝のようですね! :)それはサブクラス/パッケージに完全にトランスペアレントではないので、あまりにも悪いですが、私はそれがここでは不可能だと思います。 – gibberish

0

持っているだろう、これを行うための唯一の方法...

class A(Foo<? extends A> bar) { 
    //construct 
} 

は、しかし、これはあなたが望むものではありません表示されます。 Bのインスタンスを作成するときには、Bインスタンスの一部であるAのインスタンスも作成しているため、他のアプローチはできません。だから、BはAの部分のための特別なフィールドを取ることができません。私はあなたがなぜAのfooがBのタイプであることを許可しないのか分かりません。

+0

まあ、Fooはジェネリックパラメータ型の要素の集合を保持し、これらの要素とFooは双方向リンクを持っています。おそらく私はそれを言及すべきでした。だから私がBを含んでいるFooを持っているなら、私はそれにAをリンクさせたくありません。 – gibberish

0

私のためにコンパイル次のセットアップ:

public interface MarkerInterface { 

} 

public class A implements MarkerInterface { 

    public A(Foo<A> fooA) { 

    } 
} 

public class SuperB implements MarkerInterface { 

} 


public class B extends SuperB { 

    public B(Foo<? super B> fooB) { 

    } 
} 

そしてmain方法:

public static void main(String[] args) { 
    B b = new B(new Foo<SuperB>()); 
} 

は、あなたが探しているものを、このですか?

+0

提案していただきありがとうございますが、このメソッドはクラス階層を削除します。私は、AのメソッドシグネチャをMarkerInterfaceに入れることを考えていますか? BですべてのAのコードを複製することは、私にとって理想的ではないようです。 – gibberish

+0

あなたのシナリオを広げたばかりなので、あなたを助ける方法は本当に分かりません。 –

0

Javaジェネリックは強力でよく設計されています。それにもかかわらず、私たちは時々それらが欠けているのを見つける。私はあなたが望むことをする良い方法はないと思います。

Foo<X>の宣言をFoo<X extends A>に変更するのが一番簡単です。

class Foo<X> { } 

class FooA<X extends A> extends Foo<X> { } 

class A { 
    public A(FooA<? extends A> foo) { } 
} 

class B extends A { 
    public B(FooA<? super B> foo) { 
     super(foo); 
    } 
} 

(注:あなたが困っ以下を持っている場合は、Fooを見たとき、ArrayListと思う)それが受け入れられないなら、あなたはこのようなFooサブクラス化することができます

をこれは、あなたがする必要が明らかな欠点を持っていますFooではなくFooAを使用し、コードの再利用を妨げます。

関連する問題