2009-08-10 6 views
5

私は、Javaのジェネリックを理解し、問題を抱えていると私はこの例Javaの円形ジェネリック

class A<T extends B> { 

    public void fun(T t) { 

    } 
} 

class B { 
    A a; 

    public void event() { 
     a.fun(this); 
    } 

} 
に簡略化されてきた

問題は、AがBの内部で定義されていますが、Aはすでにそれを使用しているため、これは警告を生成していることですジェネリック型として。

私の最初の本能は私のデザインが間違っていることですが、この場合は変更できません。 Aはコレクションのようであり、Bはユーザーがオーバーライドするはずのコレクション内のノードのようなものです。特定のイベントが戻って親A.

への報告が義務づけBで発生する可能性があります。しかしAので、Bと一般的に定義されて、私はB.event()内のコンパイル警告を回避んか

おかげ

+0

私が見ることができる唯一の警告は、生の種類としてAの使用です。それがあなたが参照している警告でない場合は、より具体的に、どのコンパイラを使用しているか教えてください。 – skaffman

答えて

11

コード

public class A<T extends B> { 
    public void fun(T t) { 
    } 
} 

public class B { 
    A<B> a; 

    public void event() { 
     a.fun(this); 
    } 
} 

警告が打ち負かされます。ジェネリッククラス署名(A<T extends B>)によって示唆されるよう

理由タイプA

変数は、特定クラス型を使用して宣言されるべきです。

解像度

これはコンパイラの警告を解決しますが、根本的な問題が残っています。 Laurenceは、主要な問題に対する優れた説明と解決方法を提供します。

13

A a; 

あなたはAの型パラメータ(T)の型を指定する必要があります。問題は、この行に生タイプを使用していることです。

A<B> a; 

をしかし、私は、問題のあなたの文を理解していた場合、その後にも、全くジェネリックではないかもしれません。

あなたはこのような何かを行うことができます。だけでなく、おそらく便利ですにおける-間のこれらの変動のカップルがあります

class A<T extends B<? extends T>> { 
    public void fun(T t) { 

    } 
} 

class B<T extends B<T>> { 
    A<? super B<T>> a; 
    public void event() { 
    a.fun(this); 
    } 
} 

class A<T> { 
    public void fun(T t) { 

    } 
} 

class B<T extends B<T>> { 
    A<B<T>> a; 
    public void event() { 
    a.fun(this); 
    } 
}  

かさえ、この:あなたは、おそらくこのような何かをしたいです。後者の例は最も一般的です(しかし、明らかに、最も複雑です)。

は、Aの型パラメータがBであることを保証しています。B自体が汎用で、その循環型パラメータを持つため、B<? extends T>と言う必要があります(単にTはここでは機能しないと言います)。

class B<T extends B<T>>は、Javaで「自己タイプ」をエミュレートするのと同じくらい近いです。これにより、Bはそれ自体の(ほぼ)具体的なサブタイプについて話すことができます。 Bをサブクラス化するときは、「class C extends <B<C>>」のようなものがあります。これは、C.aのタイプが実際にはA<? super B<C>>であるため、便利です。

後者の例の? superビットは、Aと同じタイプのBではないBを接続する予定がある場合にのみ役立ちます。具体的に考えてみると、A<Shape>CircleShapeを拡張してBに拡張しています)とします。スーパーワイルドカードを使用すると、それらを一緒に使用できます。それがなければCircleのではなくA<Circle>が必要です。

+0

これは正しく、ワイルドカードの素晴らしい例です。 –