2012-09-12 50 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编译类标记为需要重新编译。