2012-02-27 118 views
1

我想了解使用Java反射調用變量方法可能會發生什麼。比方說,我們有一個簡單的方法:用Java反射調用變量方法?

void doAllTheThings(Object ... things) { 
    // ...which does something with all the things... 
} 

我們要動態地調用它,所以我們通過反射搶方法:

Method doItAll = Superklass.getDeclaredMethod("doAllTheThings", Object[].class); 

,並傳遞一個數組:

Object[] allTheThings = new Object[] { "abc", true, 15 }; 
doItAll.invoke(allTheThings); 

現在,這似乎並不像我的直覺想象的那樣工作;特別是,當我嘗試使用這種可變參數調用方法時,我似乎獲得IllegalArgumentException的各種色調。

我很清楚這裏有什麼東西。我的猜測是,這與變量如何編入可變參數值有關。我發現了this four year old blog post which seems to be talking about the same issue,但我無法重現那裏的'成功'案例。有關可能會發生什麼的任何想法?

回答

8

需要在Object[][]通過在這種情況下:

Object[] allTheThings = new Object[] { "abc", true, 15 }; 
doItAll.invoke(o, new Object[]{allTheThings}); 

的原因在於,所述單個things參數是由編譯器變換爲Object[]類型的單個參數,並且invoke帶有一個數組與參數值。

考慮更多的參數的方法,以使其更清晰:

void doMoreThings(Foo bar, Object ... things) { ... } 

Object[] allTheThings = new Object[] { "abc", true, 15 }; 
doMore.invoke(o, new Object[]{new Foo(), allTheThings}); 

invoke本身聲明爲可變參數,這樣就可以讓編譯器爲您創建的外部陣列。但是如果你通過Object[],它不會這樣做,因爲它認爲你已經這樣做了。因此,只要隱藏編譯器的事實:

doItAll.invoke(o, (Object)allTheThings); 
doMore.invoke(o, new Foo(), allTheThings); 

注意投在第一線,現在則編譯器不會再現在已經有一個數組,因此它創建一個。在第二行中,這是不需要的,因爲編譯器無論如何都沒有其他機會。

編輯: 請注意,你的代碼甚至不編譯,因爲你錯過了傳遞類的實例與doAllTheThings方法invoke(我把它命名爲o在我的代碼)。

+0

非常感謝回覆,特別是對編輯。 (您在編輯中遇到的疏忽解釋了爲什麼我無法獲得示例代碼來工作!) – 2012-02-27 20:07:59