2011-11-23 86 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

相關問題