2012-03-07 15 views
0

genericsを使用してjavaでクラスインスタンスをインスタンス化するにはどうすればよいですか?genericsを使用してJavaでクラスインスタンスをインスタンス化するにはどうすればよいですか?

XMLファイルからデータを読み込み、オブジェクトのインスタンスを作成して、オブジェクトの他のプロパティ(XMLファイルから読み取る)をオブジェクトに追加できるようにしようとしています。私はクラスメソッドの名前を読んでセッターを見つける必要がないので、コンストラクタ内のすべての値でオブジェクトをインスタンス化するのが最も簡単な方法だと思っていました。 T obj = new Object()が、オブジェクトのクラスをあなたのアドバイスのための

private static final boolean string_field = true; 

    private static <T> T getObject(Element e, String[] fieldNames, boolean[] fieldTypes) { 
     Object[] values = new Object[fieldNames.length]; 
     for (int i=0; i<fieldNames.length; i++) { 
      values[i] = (fieldTypes[i]==string_field)? getStringValue(e, fieldNames[i]) 
        : getIntegerValue(e, fieldNames[i]); 
     } 
     return new T(values); 
    } 

感謝を得る:私はこのような何かをやろうとしている

はので、私のようなものを持っている必要があります。

EDIT:

は、これは私の更新されたコード(未テスト)である:

public static <T> List<T> populateObjectList(Document xmlDoc, String tagName, 
      Class clazz, String[] fieldNames, Class[] fieldTypes) { 
     List<T> objList = new ArrayList<T>(); 
     NodeList nl = xmlDoc.getElementsByTagName(tagName); 
     if (nl!=null && nl.getLength()>0) { 
      for (int i=0; i<nl.getLength(); i++) { 
       Element e = (Element) nl.item(i); 
       T t; 
       try { 
        t = getObject(e, clazz, fieldNames, fieldTypes); 
        objList.add(t); 
       } catch (InstantiationException ex) { 
       } catch (IllegalAccessException ex) { 
       } catch (IllegalArgumentException ex) { 
       } catch (InvocationTargetException ex) { 
       } catch (NoSuchMethodException ex) { 
       } 
      } 
     } 
     return objList; 
    } 

    private static <T> T getObject(Element e, Class clazz, String[] fieldNames, Class[] fieldTypes) 
      throws InstantiationException, IllegalAccessException, IllegalArgumentException, 
      InvocationTargetException, NoSuchMethodException { 
     Object[] initargs = new Object[fieldNames.length]; 
     for (int i=0; i<fieldNames.length; i++) { 
      initargs[i] = (fieldTypes[i].getName().equals("int"))? 
       getIntegerValue(e, fieldNames[i]) 
       : getStringValue(e, fieldNames[i]); 
     } 
     return (T) clazz.getConstructor(fieldTypes).newInstance(initargs); 
    } 

あなたのいくつかは、私が何をしようとしている理解するであろうように、私はこれを投稿しました。

皆様のアドバイスをいただき、ありがとうございます。

+0

タイプの消去に問題がある可能性があります...? – Steven

+0

私はこのコードが間違っていることを知っています。私はこれを使って達成しようとしていることを説明しました。私は、値の配列にパラメータ値を持つ型Tのオブジェクトをインスタンス化したいと思います。 – Ozzy

+0

@ user1031312:どのようなタイプの 'T 'があると思いますか?それは何とか「要素」に基づいて決定されていますか?もしそうなら、おそらく 'Map >'という要素名をクラスにマッピングするのが望ましいでしょう。テイモンの答えに従ってオブジェクトを構築することができます。あるいは、おそらくあなたの 'getObject()'メソッドは 'Class 'を引数として取るべきです。 –

答えて

4

ジェネリック型をインスタンス化することはできません。 Javaのジェネリックスはというタイプの消去という厄介な機能を持っています。は、実行時にジェネリッククラスやメソッドにどのような型が使用されたのかをJVMが知らないことを意味します。これは、コレクションなどの汎用クラスのプリジェネリックバージョンとの下位互換性のためです。あなたは何ができるか

は、これをメソッドの終わりに取って代わる、あなたのパラメータリストにClass<T> clazzを追加です:

Class<?>[] paramTypes = new Class[values.length]; 
for (int i = 0; i < paramTypes.length; i++) { 
    paramTypes[i] = values[i].getClass(); 
} 
return clazz.getConstructor(paramTypes).newInstance(values); 

クラスが取るコンストラクタを持っていない場合、これは例外がスローされます適切なタイプと引数の数を正しい順序で指定します。

CAVEAT:コンストラクタのパラメータ型は、オブジェクト型として正確同じである場合にのみ機能します。たとえば、values{ "Hello", new Integer(2) }の場合、SomeClass(Object, Object)というシグネチャを持つコンストラクタではなく、SomeClass(String, Integer)というシグネチャを持つコンストラクタしか見つかりません。

+0

ありがとう、あなたは例を提供するか、反射を使用してコンストラクタを呼び出す方法の正しい方向を教えてもらえますか? – Ozzy

+0

実行時に型のクラスを取得することは可能であり、そのクラスは単に不必要に複雑になります。 – Terraego

+0

特異性のために編集されました。 – Taymon

0

私は本当にあなたの問題を参照してください、obj.getClassを使用することはできませんか?

+0

あなたは私にあなたが意味するものの例を教えてくれますか?私は前にパラメータとしてクラスを渡そうとしたが、それは別のもつれに私を得た。 私はこの 'getObject(...、class clazz)'を実行してフィールド名とフィールド型を取得しようとしましたが、そこに詰まってしまったので、値を設定したいフィールド名を渡す方が簡単だと思ったXMLファイル – Ozzy

+0

あなたは今何をしようとしているのか分かりませんが、ここではオブジェクトのコレクションを返すほうが良いと思います。あるいは、intのコレクションを返すメソッドと、文字列のコレクションを返すメソッド。 もう1つの方法は、おそらくラッパーオブジェクトになります – Terraego

1

new T()実行時にTが実質的にただObjectであるため、実行できません。コンパイラはタイプチェックにジェネリックスを使用します(たとえばにIntegerを入れることはできません)。その後、ジェネリックス情報を放棄します。すべての型の引数に対してコンパイルされたメソッドのコピーが1つあります。したがって、どの型をインスタンス化するかを知る方法はありません。

詳細については、type erasureを参照してください。

2

あなたはに単一のObject[]引数を取ったコンストラクタが含まれていることをどのように知っていますか?これを修正する方法は抽象的なファクトリを渡すことです。

interface ThingFactory { // Choose an appropriate name. 
    T create(Object[] values); 
} 

private static <T> T getObject(
    ThingFactory<T> factory, Element e, String[] fieldNames, boolean[] fieldTypes 
) { 
    ... 
    return factory.create(values); 
} 

Tも、かなり奇妙なObject[]コンストラクタを持っていない可能性があります。 Tは抽象型である可能性があります。ファクトリは引数に応じて異なる型を返すかもしれません。おそらくこれらの製品は、キャッシュ可能な不変のオブジェクトです。

+0

ああ、オブジェクトの配列はパラメータリストのvarargsのように振る舞いました。IDEではパラメータが "Object ... initargs"となり、javadocはこう言っています: 'このConstructorオブジェクトによって表されるコンストラクタを使って、コンストラクタの宣言クラスの新しいインスタンスを、指定された初期化パラメータで初期化します。 ' – Ozzy

+0

@ user1031312実際に必要としない限りリフレクションは使用しません。 –

+0

これは私のプロセスをスピードアップします、なぜ私はそれをやっているのか、私はもう少し時間があるときに変更するかもしれません。 – Ozzy

関連する問題