2011-05-06 83 views
3

我有一些像這樣的代碼:結合Java泛型和反思,以避免鑄造

Object doMethod(Method m, Object... args) throws Exception { 
    Object obj = m.getDeclaringClass().getConstructor().newInstance(); 
    return m.invoke(obj, args); 
} 

我用的是稍微複雜的代碼,但是這是它的想法。調用doMethod我這樣做:

Method m = MyClass.class.getMethod("myMethod", String.class); 
String result = (String)doMethod(m, "Hello"); 

這對我來說很好(可變數量的參數和所有)。 令我感到厭煩的是在調用者中對String的必要演員。由於myMethod宣佈,它返回一個String,我想doMethod足夠聰明,改變它的返回類型也String。有沒有使用Java泛型來完成這樣的事情的方法?

String result = doMethod(m, "Hello"); 
int result2 = doMethod(m2, "other", "args"); 

回答

4

當然,

@SuppressWarnings("unchecked") 
<T> T doMethod(Method m, Class<T> returnType, Object Args ...) { 
    Object obj = m.getDeclaringClass().getConstructor().newInstance(); 
    return (T) m.invoke(obj, args); 
} 

String result = doMethod(m, m.getReturnType(), "Hello"); 

之一是袖手旁觀好奇,對於這樣的事情要求做的架構,但是這也超出了範圍:)

如果你不喜歡你也可以省去returnType的綁定,並且編譯器會自動將它轉換爲你分配返回類型的任何東西。例如,這是合法的:

@SuppressWarnings("unchecked") 
<T> T doMethod(Method m, Object Args ...) { 
    Object obj = m.getDeclaringClass().getConstructor().newInstance(); 
    return (T) m.invoke(obj, args); 
} 

演員將會是你試圖分配給它的任何東西,但我想大多數人會認爲它是可疑的。

+1

在第一個示例中,使用'returnType.cast(...)'而不是未經檢查的轉換來使其類型安全。 – mihi 2011-05-06 18:45:34

+0

+1第二個例子比較可怕,但很有趣。我將類型推斷添加到我的Java願望清單中。 – 2011-05-06 19:07:18

+0

這不會使它編譯時間類型安全,它只是隱藏編譯器警告。如果方法的返回類型與您傳入的方法不匹配,它仍將在運行時拋出ClassCastException。 – Affe 2011-05-06 23:29:34

1

你可以嘗試

public <T> T doMethod(Method m, Class<T> clazz, Object... args); 

雖然移動施法的例程本身。總的來說,你試圖做的不像聽起來很好。反思本身帶來了一些性能開銷,但也許這不關注?

+0

的原因是環繞的方法調用一些樣板。對性能開銷的嚴重性似乎有不同的看法;我願意爲了大量代碼重用犧牲一點性能,但可能會導致性能下降是不可接受的。 – 2011-05-06 19:10:15

3

我希望法已被參數化來獲取返回類型。你總是可以做自己通過捆綁方式用自己的MethodEx ......這樣做將使您提供一些相當不錯的門面太...

public class MethodEx<T> { 
    private final Method _method; 
    private final Class<T> _returnType; 

    public MethodEx(Method method, Class<T> returnType) { 
    _method = method; 
    _returnType = returnType; 
    } 

    public T invoke(Object object, Object... args) throws InvocationTargetException { 
    try { 
     return _returnType.cast(_method.invoke(object, args)); 
    } 
    // good opportunity to hide/wrap other exceptions if your 
    // usecases don't really encounter them 
    } 
} 

這僅僅是一個起點 - 你可以有工廠MethodEx上的方法,做了很多前期驗證,以確保方法是公開的,等等。

最後,如果您要緩存Method實例等並處理動態加載的類,這也是一個很好的機會防禦性地引入弱引用(對於方法和返回類型),因此您不必在整個代碼中擔心掛鉤整個類加載器。

+0

+1這種方法非常誘人,但即使在這裏,返回類型也必須顯式傳遞給構造函數。 – 2011-05-06 19:00:30

+0

@你說得對 - 但你可以寫出一種掩蓋醜陋的工廠方法。但是最終,你不能繼續傳遞 - 在編譯時,你並不總是知道通過反射調用的方法的返回類型是什麼,所以沒有任何技巧會讓我們完全鍵入checked。所討論的所有方法都有助於減少未檢查警告需要抑制的地方的數量。 – 2011-05-06 20:52:20