2011-11-23 10 views
6

具体的なサブクラスのインスタンスを返す抽象ファクトリを使用しています。実行時に具象クラス名のStringを指定してサブクラスをインスタンス化したいと考えています。私はまた、コンストラクタにパラメータを渡す必要があります。次のようにクラスの構造は次のとおりです。java.lang.NoSuchMethodException: Child.<init>()、スタックトレースが続く:上記パラメータでランタイムにJavaインスタンス化クラス

abstract class Parent { 

    private static HashMap<String, Child> instances = new HashMap<String,Child>() 

    private Object constructorParameter; 

    public static Child factory(String childName, Object constructorParam){ 

    if(instances.keyExists(childName)){ 
     return instances.get(childName); 
    } 

    //Some code here to instantiate the Child using constructorParam, 
    //then save Child into the HashMap, and then return the Child. 
    //Currently, I am doing: 
    Child instance = (Child) Class.forName(childClass).getConstructor().newInstance(new Object[] {constructorParam}); 
    instances.put(childName, instance); 
    return instance; 
    } 

    //Constructor is protected so unrelated classes can't instantiate 
    protected Parent(Object param){ 
    constructorParameter = param; 
    } 

}//end Parent 

class Child extends Parent { 
    protected Child(Object constructorParameter){ 
     super(constructorParameter); 
    } 
} 

私attmeptは、次の例外をスローしています。

何か助けていただければ幸いです。ありがとう!

答えて

13
​​

getConstructor方法は、コンストラクターを区別するClass引数を取ります。しかし、公共のコンストラクタしか返さないので、getDeclaredConstructor(..)が必要です。次に、あなたは必要でしょうsetAccessible(true)

+0

あなたのテストに追加します。

あなたは、単に次のようにコンストラクタを呼び出すことができます。コンストラクタシグネチャを変更する必要がありますか?現時点では、シグネチャは、Object型のパラメータを明示的に期待するのではなく、より具体的なものを期待しています。 – bibs

+0

あなたの 'constructorParam.getClass()'は、あなたが期待している正確なパラメータ型を返さなければなりません。 – Bozho

+0

あなたの例に基づいて、constructorParam.getClass()が何をしているのか分かりません。あなたの答えをよりよく説明できますか?ありがとう! – trusktr

3

エラー:間違ったコンストラクタを呼び出すと、コンパイラはあなたを助ける方法がありません。

問題は、単純に引数のあるコンストラクタではなく、引数のないコンストラクタにアクセスしていたことです。 Javaのコンストラクタは、最終的には特別なものですが、ちょうどメソッドであることを覚えておいてください。リフレクションでは、すべてのベットはオフです。何かばかげてしまうと、コンパイラは役に立ちません。あなたのケースでは、スコープの問題とメソッド署名の問題が同時に発生しました。この問題を解決するため、決してが直接をテストし、その後に置くことができ、静的なヘルパーメソッドでコンストラクタ呼び出しをラップするために、このアプリケーションでは、再びそれを

その良いアイデアを対処しなければならない方法

私の単体テストで明示的にテストします。コンストラクタが変更され、リフレクションコードを更新するのを忘れてしまった場合、これらの潜在的なエラーが再びうかがえることになります。

public static Child create(Integer i, String s) throws Exception 
{ 
    Constructor c = Class.forName(childClass).getConstructor(new Object[]{Integer.class, String.class}); 
    c.setAccessible(true); 
    Child instance = (Child) c.newInstance(new Object[]{i , s}) ; 
    return instance; 
} 

をし、もちろん、私はこれを試してみましたが、まだ同じエラーを見てい

@Test 
    public void testInvoke() 
    { 
     try{ 
    MyClass.create(1,"test"); 
    } 
    catch(Exception e) 
    { 
     Assert.fail("Invocation failed : check api for reflection classes in " + MyClass.class); 
    } 
    } 
+0

実際にここでコンストラクタにパラメータを渡しますか? – bibs

+0

@bibs申し訳ありません、私はその「マイナーな」詳細を残しました。動的なコンストラクタの呼び出しは、オブジェクト配列を引数として取ります。この配列は、Class.getConstructor ...メソッドから取得したコンストラクタシグネチャと一致する必要があります。 – jayunit100

関連する問題