最初のポイント:Class c
引数をに置き換えることで、チェックされていない操作の警告を削除できますClass<T> c
。それはあなたが必要とするすべてかもしれません...その場合... =:-)
2 番目のポイント: 通常、 SomeContainer.subset() を呼び出すコードは、コンパイル時に (ロジック コンテキストから) タイプ U を認識します。そうでなければ、Class c
引数を渡すことができません。
試す:
class SomeContainer<T> extends ArrayList<T>{
public <U extends T> SomeContainer subset(Class<U> c){
SomeContainer<U> output = new SomeContainer<U>();
// put filtered elements into output
return output;
}
}
私がそこで何をしたか見てください。
メソッド呼び出しに 2 番目のタイプ パラメータを導入しました: U extends T
。との引数でもこれを使用しましたClass<U> c
。
呼び出し元は次のように呼び出します (ここで、X は T のサブクラスとして選択されます)。
SomeContainer<X> mySubset = mySomeContainer.subset(X.class); // type inference
SomeContainer<X> mySubset = mySomeContainer.<X>subset(X.class); // type arg specified
これよりも動的なものが必要な場合は、ワイルドカードが役立ちます。パラメーター化された型の「ファミリー」を入出力できるようにします。
public SomeContainer<? extends X> subset(Class<? extends X> c){
これは「プラスチック」関数インターフェイスです。T のサブクラスである任意の X に対してSomeContainer<T>
orを返すことができます。以下も機能します。SomeContainer<X>
public SomeContainer<? super Z> subset(Class<? extends X> c){
ただし、別のポスターが言ったように、ジェネリックはコンパイル時の構造であり、コンパイル中に生成された非ジェネリック コードに置き換えられます。つまり、1 行のコードでジェネリック型をインスタンス化するために使用する型を動的に決定することはできません。ただし、少しごまかすことができます。T のサブクラスの数が限られている場合、たとえば X、Y、Z のように、Z が Y を拡張し、Y が Z を拡張する場合、古き良きハッキーな「if ステートメント」を使用できます。試す:
class SomeContainer extends ArrayList{
public SomeContainer<? extends X> subset(Class<? extends X> c){
SomeContainer<? extends X> output = null;
// would like to use: "if (c instance of Class<Z>)"
// but instanceof does not allow generic type arguments
if (c.getName().equals(Z.class.getName())) {
SomeContainer<Z> outputZ = new SomeContainer<Z>();
// put filtered elements into outputZ
output = outputZ;
} else if (c.getName().equals(Y.class.getName())) {
SomeContainer<Y> outputY = new SomeContainer<Y>();
// put filtered elements into outputZ
output = outputY;
} else if (c.getName().equals(X.class.getName())) {
SomeContainer<X> outputX = new SomeContainer<X>();
// put filtered elements into outputZ
output = outputX;
}
return output;
}
}
簡単!(またはしない) =:-)