繁体   English   中英

Java在运行时使用参数实例化类

[英]Java Instantiate Class at Runtime with parameters

我正在使用一个抽象工厂来返回具体子类的实例。我想在给定具体类名的String的情况下在运行时实例化子类。 我还需要将参数传递给构造函数。 类结构如下:

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);
    }
}

我上面提到的是抛出以下异常: java.lang.NoSuchMethodException: Child.<init>() ,后跟堆栈跟踪。

任何帮助表示赞赏。 谢谢!

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

getConstructor方法使用Class参数来区分构造函数。 但它只返回公共构造函数,因此您需要getDeclaredConstructor(..) 那你需要setAccessible(true)

错误:您正在调用错误的构造函数 - 编译器无法帮助您。

你遇到的问题只是你访问零参数构造函数,而不是带参数的构造函数。 请记住,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);
   }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM