2012-09-22 11 views
12

Iは、同じタイプ(タイプの特定のセットのいずれかとすることができるタイプ)の2つの値の組を表すクラスがありますJava Genericsの制限または誤った使用ですか?

public class Pair<E extends AClass>{ 
     private E var1; 
     private E var2; 
    } 

このクラスは、フレームワークによって使用されるので、それはないが必要されます

  1. で:ここで多くの問題が明らかに存在する

    public class Pair<E extends AClass>{ 
         private E var1; 
         private E var2; 
    
         public Pair(){ 
          var1 = invoke constructor of type E; 
          var2 = invoke constructor of type E 
         } 
        } 
    

    :私が持っている-argumentコンストラクタは、2つの変数(VAR1、VAR2)をインスタンス化します私は何とかその正確な型を知って、その型のコンストラクタを呼び出さなければならない変数をインスタンス化するために、 var1がタイプEの宣言とIされているので、私は上記のように、私はいくつかの問題を持ってない場合でも

    public Pair(){ 
         if(var1 instanceof SpecificType1){ 
          var1 = new SpecificType1(); 
          var2 = new SpecificType2(); 
         } 
        } 
    
  2. :最良のケースでは、これは、コンストラクタ内の他のif文のようなものがかなり大きなを持つことを意味しSpecficType1をインスタンス化し、結果オブジェクトをvar1/var2に割り当てるときに、型の不一致エラーが発生します。それを動作させるためには、私はEにキャストする必要があります。

    var1 = (E)new SpecificType1(); 
    

をしかし、私はジェネリック型に特定のタイプをキャストしようとしているとして、これは、コンパイル時の型チェックを破壊します。

これはJavaのGenericsの制限ですか、このシナリオはGenericsを使用すると悪いですか?

+1

ジェネリックコンテナ内で 'instanceOf'を使用する必要がある場合は、設計に問題があります。 –

+0

[Class.forName()](http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Class.html#forName%28java.lang.String%29)を試すと、 –

+0

質問者への通知(編集者が質問者に通知しないので):あなたのケースで工場設計パターンを使用する方法を簡単なコードサンプルに追加しました – amit

答えて

6

変数をインスタンス化するために、どういうわけかその正確な型を知って、その特定の型のコンストラクタを呼び出す必要があります。最良の場合、これはコンストラクタ内にかなり大きいif else文を持つことを意味します。

これまでに問題が発生します。

if(var1 instanceof SpecificType1){ 
     var1 = new SpecificType1(); 
     var2 = new SpecificType2(); 
    } 

var1この時点でnullので、var1 instanceof TはすべてTためfalseです。 Javaのジェネリックの


1つの制限は、ジェネリック型パラメータがerasedはそうあなたがゼロ引数コンストラクタからの型パラメータに反映させることができる方法はありませんということです。

var1var2を初期化する方法を説明するための呼び出し元が用意されている必要があります。そのコンテキストを提供する一般的な方法は、コンストラクタ引数を使用する方法です。


あなたの最良のオプションは、var1聞かせvar2nullを始めると、あなたはあなたが必要なコンテキストを得ることができるような時間まで、初期化を遅らせることが考えられます。あなたはまだE extends List<Number>からE extends List<String>を区別することはできませんが、それはあなたの場合には十分であってもよく、.cast方法はあなたに、タイプセーフなキャストを与えるので、

はおそらく

void init(Class<E> type) { 
    if (type.isAssignableFrom(ConcreteType1.class)) { 
    var1 = type.cast(new ConcreteType1(...)); 
    var2 = type.cast(new ConcreteType1(...)); 
    } else { /* other branches */ } 
} 

これは完璧ではありませんE。また


、グアバ、Guiceの、および関連ライブラリがinit方法で便利になることがありSupplier<E>インタフェースのようなものを提供します。

+0

はい、これも私の直感でした。だから、限界はさらに深刻です! – Razvan

+0

私も編集に同意します。私はパラメータとして2つのE変数を取る別のコンストラクタを持っていますが、フレームワークは引数なしのコンストラクタを必要としています – Razvan

+0

フレームワークはinitを呼び出すはずです。 – Razvan

2

ジェネリック型をインスタンス化できません。たとえばジェネリック型がSomeAbstractClassの場合はどうなりますか?何がインスタンス化されますか?

しかし、java reflection APIを使用してオブジェクトをインスタンス化することはできますが、特定のクラスオブジェクトが必要になります。

abstract factory design patternを使用して、ファクトリオブジェクトをペアに渡し、必要なオブジェクトを構築するために使用します。


コードサンプル:

public class Pair<S> { 
    public final S var1; 
    public final S var2; 
    public Pair(Factory<S> builder) { 
     var1 = builder.build(); 
     var2 = builder.build(); 

    } 
} 

public interface Factory<S> { 
    public S build(); 
} 

public class IntegerBuilder implements Factory<Integer> { 
    private int element = 5; 
    public Integer build() { 
     return new Integer(element++); 
    } 
} 
+0

サンプルコードは、いつでも歓迎します。 – OldCurmudgeon

+0

@OldCurmudgeon:ちょっと、分かりましたか? – amit

+0

優れています。そして今、 'Class'メソッドのために、完全性のために。 – OldCurmudgeon

1

フレームワークは、それをインスタンス化した場合、それは、生タイプとしてなし型パラメータを持つnew Pair()と同等のものを、それを行うだろう。

class SpecificType1Pair extends Pair<SpecificType1> {} 

、代わりにフレームワークに渡す:

私はあなたのような簡単なワンライナーのクラスを作成する必要がありますね。実際の型パラメータはgetClass().getGenericSuperclass()).getActualTypeArguments()[0]です。あなたのクラスペアは次のようになります:

public abstract class Pair<E extends AClass> { 
    private E var1; 
    private E var2; 

    public Pair() { 
     ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); 
     @SuppressWarnings("unchecked") 
     Class<E> clazz = (Class<E>) superclass.getActualTypeArguments()[0]; 
     try { 
      var1 = clazz.newInstance(); 
      var2 = clazz.newInstance(); 
     } catch (InstantiationException e) { 
      handle(e); 
     } catch (IllegalAccessException e) { 
      handle(e); 
     } 
    } 
} 
+1

クラス clazz =(Class )...; '行の' @SuppressWarnings( "未チェック") 'が順番に並んでいる可能性があります。 –

関連する問題