8

この質問をするのは良くないことはわかっています。この質問をすると呪われるかもしれませんが、この質問について助けを求める場所が見つかりません。

以下は、私のインタビューの質問に出てきた汎用クラスです (私はすでに失敗しています)。問題は、この Class 宣言が何をしているのか、またどのような状況でこれを使用できるのかを伝えることでした。

汎用プログラミングについての理解は非常に限られていますが、「T」はタイプであり、ここで「拡張」とは、タイプが「SimpleGenericClass」を継承する必要があることを意味しますが、「?」を理解していません。最後に、このクラスがどのような状況で使用される可能性があるか

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

}
4

5 に答える 5

4

まず、クラスSimpleGenericClassabstractであるため、サブクラス化されることを意図しています。

第 2 に、これはジェネリッククラスであるため、クラス内のどこかでジェネリック パラメータTをフィールドの型としてほぼ確実に使用できます。

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

ここで最初に興味深いのは、それTboundedであることです。それは、 または の一部のサブクラスT extends SimpleGenericClass<?>のみであると宣言されているためです。thr についても尋ねました。これはワイルドカードとして知られており、ワイルドカードに関する Java チュートリアル にかなり適切な説明があります。あなたの場合、これは「SimpleGenericClass of unknown」であると言えます。たとえば、は のスーパークラスではないため、Java で必要です。SimpleGenericClass<?>SimpleGenericClass<?>?SimpleGenericClass<Object>SimpleGenericClass<String>

2 番目に興味深いのTは、SimpleGenericClassはある種のものであるため、クラスは 再帰構造を定義している可能性が高いということです。私の頭に浮かぶのはSimpleGenericClass、あらゆる種類の特殊なノード タイプでサブクラス化されるように設計された (抽象) ノード タイプであるツリー (式ツリーと考えてください) です。

UPDATE 自己境界ジェネリックに関するこのSOの質問は、あなたに役立つかもしれません。

更新 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それは実際には重要ですか?わかりませんが、かなりクールです。:)

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

于 2011-09-24T07:43:24.257 に答える
0

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

public abstract class SimpleGenericClass<T extends SimpleGenericClass<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(like )のサブクラスは、Barそれらが提供する型引数Fooがそれ自体であるというイディオムに従います。

  • Foo には を返すメソッドがありますSubClassOfFoo。上記のイディオムと組み合わせると、Foo は「私のサブクラスは実装subclassAwareDeepCopy()する必要があり、実際のサブクラスを返すことを宣言しなければならない」というコントラクトを作成できます。

別の言い方をすると、このイディオムにより、スーパークラス (Abstract Factory など) は、引数の型と戻り値の型がスーパークラスの型ではなく、サブクラスの型に関するメソッドを定義できます。

このトリックは、たとえばEnumJDK クラスで行われます。

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

詳細については、こちらを参照してください。

于 2011-09-24T07:59:04.280 に答える
0

これは実際には、クラス SimpleGenericClass のユーザーが型 T を持つクラスのインスタンスをパラメーター化できるようにすることを意味するだけです。ただし、T は任意の型にすることはできず、SampleGenericClass (または SampleGenericClass 自体) のサブタイプである必要があります。

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

ちょっとの間、SimpleGenericClass は抽象的ではないと仮定しましょう。それを使用するときは、次のように書くことができます。

new SimpleGenericClass<SampleGenericClass<String>>();

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

于 2011-09-24T07:26:25.283 に答える
0

定義によると、は SimpleGenericClass のサブクラスでSimpleGenericClassある型で機能します。<T>

したがって、動作する操作がいくつかあると思い<T>ます。

なぜこのようなテンプレートを定義するのかを見てみましょう - (私が考えることができることはあまりありません)SimpleGenericClassは、抽象クラス ( OP :P に従っていることに気づきました) であり、それが機能することを期待しているシナリオである可能性があります具体的なクラスはありますか?

皆さんどう思いますか?

于 2011-09-24T07:43:13.747 に答える
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<?>時点ではかなり冗長です。このクラスで別のジェネリック型が必要な場合は、複数 ( SimpleGenericClass<T extends SimpleGenericClass, T2 extends Whatever>)を持つことができます。

于 2011-09-24T07:44:43.060 に答える