web-dev-qa-db-ja.com

ジェネリックコンストラクターはどのような目的でJavaで機能しますか?

誰もが知っているように、型引数を使用することでJavaでジェネリッククラスを持つことができます:

class Foo<T> {
    T tee;
    Foo(T tee) {
        this.tee = tee;
    }
}

ただし、ジェネリックconstructorsを使用することもできます。これは、たとえば次のように、独自のジェネリック型引数を明示的に受け取るコンストラクタを意味します。

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

ユースケースを理解するのに苦労しています。この機能により何ができますか?

33
0xbe5077ed

この機能により何ができますか?

少なくともある  他の方法ではできなかったことができる2つのこと:

  1. 引数のタイプ間の関係を表現します。例:

    class Bar {
        <T> Bar(T object, Class<T> type) {
            // 'type' must represent a class to which 'object' is assignable,
            // albeit not necessarily 'object''s exact class.
            // ...
        }
    }
    
  2. <撤回>

  3. @Linoが最初に観察したように、引数は2つ以上の無関係な型の組み合わせと互換性がなければならないことを表現できます(せいぜい1つを除くすべてがインターフェイス型である場合に意味があります)。例については、リノの回答を参照してください。

15
John Bollinger

私が考えているユースケースは、2つのタイプを継承するオブジェクトが必要な場合があります。例えば。 2 interfacesを実装します:

public class Foo {

    public <T extends Bar & Baz> Foo(T barAndBaz){
        barAndBaz.barMethod();
        barAndBaz.bazMethod();
    }
}

実稼働では使用したことがありませんが。

23
Lino

実行時にUになるので、クラスのコンストラクターでObjectが役割を果たさないことを提供した例では明らかです。

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

しかし、以下に示すように、コンストラクターが他のクラスまたはインターフェースを拡張する型のみを受け入れるようにしたいとします。

class Foo<T extends Baz> {
    <U extends Bar> Foo(U u) {
        // I must be a Bar!
    }
}

クラスにはすでに使用中の異なるジェネリック型があることに注意してください。これにより、クラス定義に別個の無関係なジェネリック型を利用できます。

確かに、私はこのようなものを使用したことはなく、使用中に見たこともありませんが、可能です!

19
Jacob G.

実際、このコンストラクタ

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

一般的な方法 のようなものです。次のような複数のコンストラクター引数がある場合は、さらに意味があります。

class Bar {
    <U> Bar(U you, List<U> me) {
        // Why!?
    }
} 

次に、コンパイラと同じ時間を持つという制約を強制できます。 Uをクラス全体のジェネリックにすることなく。

10
keuleJ

この非バインドジェネリック型はObjectに消去されるため、コンストラクターでObjectを渡すのと同じになります。

public class Foo {
    Object o;

    public Foo(Object o) {
        this.o = o;
    }
}

...しかし、空のObjectを渡すのと同様に、何か巧妙なをしているのでない限り、これは実用的な価値がほとんどありません。

代わりにbound genericsを渡すと、利点と利点が得られます。つまり、実際に関心のある型について保証することができます。

public class Foo<T extends Collection<?>> {
    T collection;
    public Foo(T collection) {
        this.collection = collection;
    }
}

事実上、これは革新的なものというよりも柔軟性に関するものです。特定のタイプのカテゴリを柔軟に渡す必要がある場合は、ここで行うことができます。 do n'tの場合、標準クラスに問題はありません。それは単にあなたの便宜のためにここにあります、そして型消去はまだ事であるので、バインドされていないジェネリックはObjectを渡すのと同じです(そして同じユーティリティを持っています)。

8
Makoto