2016-06-01 6 views
0

私はリフレクションを使用して、抽象クラスを実装するクラスのリストを取得しようとしています。Detectorこのリストの要素(タイプClass<T extends Detector>)を別のクラスの型パラメータとしてDetectorWrapper<T extends Detector>に使用して、そのクラス内でT(つまりnew T(...)を使用)を簡単にインスタンス化できるようにしたいと思います。これに対してリフレクションを使用することは可能ですか、代わりにClass<T>DetectorWrapperに渡して、Tのインスタンスが必要なときにリフレクションを使用してコンストラクタを呼び出す必要がありますか?クラス<T>を型パラメータとして使用

+0

この質問はリンクされた質問の複製ではありません。私は検索でこれらの解決策を見つけましたが、私が望むものとは正反対です**。リンクされた質問では、タイプ「T」が検索される。私は与えられた反射パラメータ化型の型を問い合わせるのではなく、型パラメータとして反映型を使いたいと思います。私はこれを明確にするために質問を改善する方法がわからない。 –

答えて

1

タイプパラメータとしてClassオブジェクトを使用する方法はありませんが、タイプパラメータはまったくインスタンス化できないもの、つまりnew T()とは言えません。

ですから、その型のオブジェクトをインスタンス化するClassオブジェクトが必要と型パラメータに関係を定義することがあります。

class DetectorWrapper<T extends Detector> { 
    final List<T> detectors; 

    DetectorWrapper(Class<? extends T>... types) { 
     ArrayList<T> result=new ArrayList<>(types.length); 
     try { 
      for(Class<? extends T> type: types) result.add(type.newInstance()); 
     }catch(InstantiationException|IllegalAccessException ex) { 
      throw new IllegalArgumentException(ex); 
     } 
     this.detectors=result; 
    } 
} 

最も実用的な問題のために、DetectorWrapperクラスの型パラメータが廃止されていますが、つまり、あなたは

class Detector {} 
class Foo extends Detector {} 
class Bar extends Detector {} 
のようなクラスを持つ

class DetectorWrapper { 
     final List<Detector> detectors; 

     DetectorWrapper(Class<? extends Detector>... types) { 
      ArrayList<Detector> result=new ArrayList<>(types.length); 
      try { 
       for(Class<? extends Detector> type: types) result.add(type.newInstance()); 
      }catch(InstantiationException|IllegalAccessException ex) { 
       throw new IllegalArgumentException(ex); 
      } 
      this.detectors=result; 
     } 
    } 

を使用することができます

new DetectorWrapper(Foo.class, Bar.class)DetectorWrapperをインスタンス化できます。

Class.newInstance()は、引数なしのコンストラクタを前提としています。共通のコンストラクタシグネチャが分かっている場合は、代わりにtype.getConstructor(parameterTypes).newInstance(initargs);を使用してください。上記と同じ設定を仮定し、new DetectorWrapper(Foo::new, Bar::new)ようにインスタンス化することができる

class DetectorWrapper { 
    final List<Detector> detectors; 

    DetectorWrapper(Supplier<? extends Detector>... types) { 
     ArrayList<Detector> result=new ArrayList<>(types.length); 
     for(Supplier<? extends Detector> s: types) result.add(s.get()); 
     this.detectors=result; 
    } 
} 

のJava 8で

は、より堅牢な、非反射の代替があります。

class DetectorWrapper { 
    final List<Detector> detectors; 

    DetectorWrapper(Supplier<? extends Detector>... types) { 
     detectors=Arrays.stream(types).map(Supplier::get).collect(Collectors.toList()); 
    } 
} 

しかし、あなたは、実行時に動的にClassオブジェクトを発見した場合、反射インスタンス化回避する方法はありません。

同等の代替の実装は次のようになります。

+0

奇妙なことに、 ' 'を指定すると、' new T() 'はコンパイルされたように見えますが、なぜそれが悪いのか分かります。私は 'T 'を使って、' Detector'で定義したいくつかの静的メソッドを呼び出すこともできました。このメソッドは、このユースケースの追加動機です。広範な答え、特に非反射的な例をありがとう! –

+1

'T 'が型パラメータを参照している場合、' new T() 'は動作できません。範囲や別の誤解の中におそらく異なる「T」があります。 「T.method」を使用して 'Detector 'の' static'メソッドを呼び出すことは効果がありません(もし 'T''が' Detector'に比べて型が少ないと思うなら 'import static'を考えてください)。 '@ SafeVarargs'をコンストラクタに追加するには、実際にプロダクションコードでそれをしたいと思っています... – Holger

関連する問題