2015-01-12 50 views
5

大家都知道可以使用Reflection獲取方法,並通過返回的Method實例調用它。由Reflection獲取的方法的執行是否需要更長的時間?

然而我的問題是;一旦它被Reflection提取並且我反覆調用Method,那麼該方法的性能會比調用方法的正常方式慢嗎?

例如:

import java.lang.reflect.Method; 

public class ReflectionTest { 

    private static Method test; 

    public ReflectionTest() throws Exception { 
     test = this.getClass().getMethod("testMethod", null); 
    } 

    public void testMethod() { 
     //execute code here 
    } 

    public static void main(String[] args) throws Exception { 
     ReflectionTest rt = new ReflectionTest(); 
     for (int i = 0; i < 1000; i++) { 
      rt.test.invoke(null, null); 
     } 

     for (int i = 0; i < 1000; i++) { 
      rt.testMethod(); 
     } 
    } 
} 

我問這個,因爲我在做一個事件系統,該系統在註冊監聽器,它會掃描註解。將這些方法放入一張圖中,然後在每次發生其所需參數類型的事件時執行這些方法。我不知道這是否足夠高性能,例如遊戲。

+1

也許不在執行中,也許在抓取? – DnR

+0

我相信如果我注意提取的數量,我不應該對性能有太大的影響嗎? – Limnic

+0

讓我們等待親的答案:D – DnR

回答

3

使用沒有反射的方法大約快一個數量級。我測試它像

public static void main(String[] args) throws Exception { 
    ReflectionTest rt = new ReflectionTest(); 
    // Warm up 
    for (int i = 0; i < 100; i++) { 
     test.invoke(rt, null); 
    } 
    for (int i = 0; i < 100; i++) { 
     rt.testMethod(); 
    } 

    long start = System.nanoTime(); 
    for (int i = 0; i < 10000; i++) { 
     test.invoke(rt, null); 
    } 
    long end = Math.abs((start - System.nanoTime())/1000); 
    start = System.nanoTime(); 
    for (int i = 0; i < 10000; i++) { 
     rt.testMethod(); 
    } 
    long end2 = Math.abs((start - System.nanoTime())/1000); 
    System.out.printf("%d %d%n", end, end2); 
} 

我也感動teststatic字段,以便將編譯和運行

private static Method test; 
static { 
    try { 
     test = ReflectionTest.class.getMethod("testMethod"); 
    } catch (NoSuchMethodException e) { 
     e.printStackTrace(); 
    } catch (SecurityException e) { 
     e.printStackTrace(); 
    } 
} 

我得到一個相當一致的差異(或輸出一致)與

4526 606 

這表明在10000調用中反射速度比直接調用慢7倍。

+0

嗯。這很讓人失望:(我真的很喜歡我的事件系統的工作方式,同樣的測試在我的電腦上使用了'1740 228'。你認爲我應該保持事件系統的狀態嗎?或者你有什麼好的建議嗎?系統? – Limnic

+0

老實說,我認爲這可能是一個過早優化的例子,反射給你的額外的靈活性似乎是值得的懲罰,如果有一些關鍵路徑,那麼你可以優化,當你找到它 –

+0

@Limnic - 如何你是否期望有人回答......除非他們已經*看到*你的事件系統的代碼?是的,「不成熟的優化」!! –

2

@Elliot Frisch的回答提供了結論性的證據表明使用Method.invoke()比較慢。

無論如何,你會期待這一點,因爲反射版本涉及額外的工作;例如

  • 創建和含有varags數組的初始化,
  • 檢查陣列的長度,並
  • 鑄造陣列中的參數從Object到相應的參數類型。

這是可能的JIT可能會在某些情況下,優化這個...


1 - OK ......沒有定論。基準值得懷疑,因爲它沒有正確處理可能的JVM熱身異常。

相關問題