2011-09-24 24 views
8

(私はこれを聞いて良い質問ではありません知っていると私はそれを聞いて呪われ得るかもしれないが、私はこの質問の下この汎用クラス宣言は何を意味するのでしょうか?

に関するヘルプを表示するには任意の場所には、私の面接の質問に登場ジェネリッククラスで見つけることができません私はすでに失敗しました)。問題は、このクラスの宣言が何をしているのか、どのような状況でこれを使用できるのかを知ることでした。

私はジェネリックプログラミングの理解が非常に限られていますが、 'T'はタイプであり、 'extends'はタイプが 'SimpleGenericClass'を継承する必要があることを意味しますが、 '?このクラスは、潜在的に

public abstract class SimpleGenericClass<T extends SimpleGenericClass<?>> { 

} 
+2

両方とも「シンプル」か「サンプル」か、それとも異なるクラスであると思われますか? –

+0

ごめんなさい、そのSimpleGenericClass - 私はそれを更新しました。ありがとう – anonymous

答えて

4

まず、クラスSimpleGenericClass抽象であるため、サブクラス化することを意味します。

genericクラスです。つまり、クラス内でフィールドのタイプとして汎用パラメータTを使用していることがほぼ確実にわかります。

public abstract class SimpleGenericClass<T...> { 
    T x; 
} 

今ここ最初興味深いのは、T有界であるということです。 T extends SimpleGenericClass<?>と宣言されているため、SimpleGenericClass<?>またはSimpleGenericClass<?>のサブクラスしか指定できません。あなたはまたthr ?について尋ねました。これはワイルドカードとして知られており、the Java Tutorial on Wildcardsにはかなり良い説明があります。あなたの場合、これは「SimpleGenericClass of Unknown」と言うでしょう。例えば、SimpleGenericClass<Object>SimpleGenericClass<String>のスーパークラスではないため、Javaでは必要です。

興味深いのは、しかしTはある種のSimpleGenericClassているので、あなたのクラスはおそらく再帰的な構造を定義するよりもあるということです。私の頭に浮かぶのは、SimpleGenericClassがすべての種類の特殊なノードタイプでサブクラス化されるように設計された(抽象的な)ノードタイプのツリー(表現木を考える)です。

更新This SO question on self-bounded genericsが役に立ちます。

UPDATE 2

私は先に行って、これを使用する方法を示していくつかのコードをまとめます。アプリケーションは何もしませんが、コンパイルして、ジェネリック境界がいくつかの意味のある制約をどのように提供できるかを示します。

public abstract class Node<T extends Node<?>> { 
    public abstract T[] getChildren(); 
} 

class NumberNode extends Node { 
    int data; 
    public Node[] getChildren() {return new Node[]{};} 
} 

class IdentifierNode extends Node { 
    int data; 
    public Node[] getChildren() {return new Node[]{};} 
} 

class PlusNode extends Node { 
    NumberNode left; 
    NumberNode right; 
    public NumberNode[] getChildren() {return new NumberNode[]{};} 
} 

ここの良いところは、NumberNode[]PlusNode.getChildrenの有効な戻り値の型であるということです!それは実際に重要なのでしょうか?いい考えはありませんが、それはかなりクールです。 :)

これは最高の例ではありませんが、質問はむしろオープンエンドでした(「このようなものは何のために使用されるのでしょうか」)。もちろん、ツリーを定義する他の方法もあります。

0

を使用することができる最後に、どのような状況でこれは本当に唯一のあなたはしかし、型Tを持つクラスのインスタンスをパラメータ化するクラスSimpleGenericClassのユーザーが許可されていることを意味し、Tは、いずれかをすることはできませんSampleGenericClass(またはSampleGenericClass自体)のサブタイプである必要があります。

SimpleGenericClassクラスのコードの残りの部分では、メソッドシグネチャでT型を使用できます。

SimpleGenericClassが抽象ではないとしましょう。それを使用するとき、あなたは次に書くことができます:

new SimpleGenericClass<SampleGenericClass<String>>(); 

Ie. SampleGenericClassでSimpleGenericClassを、StringでSampleGenericClassをパラメータ化します。

+0

申し訳ありませんhendrik、それはSampleGenericClassではなく、唯一のSimpleGenericClass ...私は質問を更新しました。 – anonymous

0

SimpleGenericClassは、SimpleGenericClassのサブクラスである<T>の型で動作することができます。

したがって、私は<T>で動作するいくつかの操作があると仮定します。 1は、このようなテンプレートを定義する理由今見るために

- (ずっと私は本当に、考えることができない)がSimpleGenericClassは抽象クラスであるシナリオかもしれ(はちょうどそれがOPのとおりです実現:P)どんな具体的なクラスでも動作できると期待していますか?

あなたはどう思いますか?

0

これは基本的には、このクラスではTという名前のTypeプレースホルダーがあり、そのプレースホルダーには制限があります。タイプはSimpleGenericClassかそれを拡張するものでなければなりません。あなたがそのルールに従うたら、あなたのクラスのインスタンスを作成し、Tへの実際の型を与え、その後でそのクラスのメソッドで使用することができ、このようなものができます。

public class C <T extends Number>{ 

    public void doSomething(T t) { 

    } 

    public static void main(String... args) { 
     //works: 
     C<Number> c = new C<Number>(); 
     c.doSomething(new Number() { 
      //Aonimous implementation of number 

     }); 

     //won't work 
     //C<Object> c = new C<Object>(); 

     C<Integer> c2 = new C<Integer>();  
     c2.doSomething(new Integer(1)); 
     //won't work 
     //c2.doSomething(new Number() { 

      //Aonimous implementation of number 
     //}); 
    } 
} 

SimpleGenericClass<?>が、この時はかなり重複していますポイント。

public abstract class SimpleGenericClass<T extends SimpleGenericClass<T>> 

は見てみましょう:他の一般的なタイプは、このクラスに必要とされている場合は、複数の(SimpleGenericClass<T extends SimpleGenericClass, T2 extends Whatever>

0

を持つことができ、私はあなたがこの形式の質問(T代わりの?を)持っていると思いますこのコードで:

abstract class Foo<SubClassOfFoo extends Foo<SubClassOfFoo>> 
{ 
    /** subclasses are forced to return themselves from this method */ 
    public abstract SubClassOfFoo subclassAwareDeepCopy(); 
} 

class Bar extends Foo<Bar> { 
    public Bar subclassAwareDeepCopy() { 
     Bar b = new Bar(); 
     // ... 
     return b; 
    } 
} 

Bar b = new Bar(); 
Foo<Bar> f = b; 
Bar b2 = b.subclassAwareDeepCopy(); 
Bar b3 = f.subclassAwareDeepCopy(); // no need to cast, return type is Bar 

Foo<SubClassOfFoo extends Foo<SubClassOfFoo>>で起こってトリックがある:

  • Fooのサブクラスは、タイプ引数をFooに指定する必要があります。
  • この型引数は実際にはFooのサブクラスでなければなりません。
  • Fooのサブクラス(Barなど)は、 引数がFooに供給されるという慣習に従います。

  • FooにはSubClassOfFooを返すメソッドがあります。 を上記のイディオムと組み合わせると、Fooは が「subclassAwareDeepCopy()と を実装する必要があり、そのサブクラスが実際のサブクラスを返すと宣言する必要があります」という契約書を作成することができます。このイディオムは、(例えば抽象工場など)スーパークラスは、その引数の型と戻り値の型サブクラスの種類ではなく、スーパータイプの面であるメソッドを定義することができます:別の方法と言って

トリックがEnum JDKクラスで例えば行われます

public abstract class Enum<E extends Enum<E>> 

は詳細についてはhereを参照してください。

関連する問題