7

抽象ファクトリを使用して具象サブクラスのインスタンスを返しています。具象クラス名の文字列を指定して、実行時にサブクラスをインスタンス化したいと思います。また、コンストラクターにパラメーターを渡す必要があります。クラス構造は次のとおりです。

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は、次の例外をスローしています:java.lang.NoSuchMethodException: Child.<init>()、その後にスタックトレースが続きます。

どんな助けでも大歓迎です。ありがとう!

4

2 に答える 2

14
Constructor<?> c = Class.forName(childClass).getDeclaredConstructor(constructorParam.getClass());
c.setAccessible(true);
c.newInstance(new Object[] {constructorParam});

このgetConstructorメソッドはClass、コンストラクターを区別するために引数を取ります。ただし、パブリックコンストラクターのみが返されるため、が必要になりますgetDeclaredConstructor(..)。次に、あなたが必要になるでしょうsetAccessible(true)

于 2011-11-23T21:07:39.700 に答える
4

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

あなたが抱えていた問題は、引数を持つコンストラクターではなく、引数がゼロのコンストラクターにアクセスしていたことです。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);
   }
    }
于 2011-11-23T21:27:58.607 に答える