2012-09-12 67 views
2

由於其他線程(參見https://stackoverflow.com/a/397617/1408611)來完成它表明Java 6中說的instanceof標杆實際上是相當快的。這是如何實現的?在現代JVM實現中如何實現instanceof?

我知道對於單一繼承,最快的想法是有一些嵌套的區間編碼,其中每個類保持[低,高]區間,而instanceof只是一個區間包含測試,即2個整數比較。但是它是如何爲接口創建的(因爲區間包含僅適用於單一繼承)?以及如何處理類加載?加載新的子類意味着需要調整很多時間間隔。

回答

4

據我所知每個類都知道它擴展它實現的類和接口。這些可以存儲在給出O(1)查找時間的散列集中。

當代碼往往需要在同一分支,成本幾乎可以消除因爲CPU之前已經確定是否應採取分支使旁邊沒有成本的分支可以執行的代碼。

由於微型基準測試在4年前進行的,我希望最新的CPU和JVM的要快得多。

public static void main(String... args) { 
    Object[] doubles = new Object[100000]; 
    Arrays.fill(doubles, 0.0); 
    doubles[100] = null; 
    doubles[1000] = null; 
    for (int i = 0; i < 6; i++) { 
     testSameClass(doubles); 
     testSuperClass(doubles); 
     testInterface(doubles); 
    } 
} 

private static int testSameClass(Object[] doubles) { 
    long start = System.nanoTime(); 
    int count = 0; 
    for (Object d : doubles) { 
     if (d instanceof Double) 
      count++; 
    } 
    long time = System.nanoTime() - start; 
    System.out.printf("instanceof Double took an average of %.1f ns%n", 1.0 * time/doubles.length); 
    return count; 
} 

private static int testSuperClass(Object[] doubles) { 
    long start = System.nanoTime(); 
    int count = 0; 
    for (Object d : doubles) { 
     if (d instanceof Number) 
      count++; 
    } 
    long time = System.nanoTime() - start; 
    System.out.printf("instanceof Number took an average of %.1f ns%n", 1.0 * time/doubles.length); 
    return count; 
} 

private static int testInterface(Object[] doubles) { 
    long start = System.nanoTime(); 
    int count = 0; 
    for (Object d : doubles) { 
     if (d instanceof Serializable) 
      count++; 
    } 
    long time = System.nanoTime() - start; 
    System.out.printf("instanceof Serializable took an average of %.1f ns%n", 1.0 * time/doubles.length); 
    return count; 
} 

最後打印

instanceof Double took an average of 1.3 ns 
instanceof Number took an average of 1.3 ns 
instanceof Serializable took an average of 1.3 ns 

如果我改變了 「雙打」 與

for(int i=0;i<doubles.length;i+=2) 
     doubles[i] = ""; 

我得到

instanceof Double took an average of 1.3 ns 
instanceof Number took an average of 1.6 ns 
instanceof Serializable took an average of 2.2 ns 

注:如果我改變

if (d instanceof Double) 

if (d != null && d.getClass() == Double.class) 

的性能是一樣的。

+0

我也在想這個散列表方法。但是在某些情況下,instanceof似乎比散列表查找更快。它比沒有參數的單個函數調用還要快。 – gexicide

+0

生成的代碼可以內聯。對於上面的'Double'的情況,由於類是'final',所以測試與'd!= null && d.getClass()== Double.class'相同 –

0

我不知道這是怎麼處理的,但你可以通過查看JIT編譯器的源代碼中找到,或通過傾倒編譯的本地代碼的一些例子的JIT。

又是怎樣的類裝載處理?加載新的子類意味着需要調整很多時間間隔。

在幾種情況下,JIT編譯器根據假設當前加載的類是所有的情況進行優化。如果加載了新類,我知道編譯器會將受影響的JIT編譯類標記爲需要重新編譯。