2011-11-23 87 views
6

我正在使用抽象工厂来返回具体子类的实例。我想在运行时实例化子类,给定具体类名的字符串。我也需要传递一个参数给构造函数。类结构如下:在运行时的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上述抛出以下异常:java.lang.NoSuchMethodException: Child.<init>(),其次是堆栈跟踪。

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

回答

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

相关问题