如何在现代JVM实现中实现instanceof?

由于在其他线程中完成了基准测试(参见https://stackoverflow.com/a/397617/1408611 ),因此可以看出Java 6中的instanceof实际上非常快。 这是如何实现的?

我知道对于单inheritance,最快的想法是有一些嵌套的间隔编码,其中每个类维持一个[低,高]间隔,而instanceof只是一个区间包含测试,即2个整数比较。 但它是如何制作接口的(因为区间包含仅适用于单inheritance)? 如何处理类加载? 加载新的子类意味着必须调整很多间隔。

AFAIK每个类都知道它扩展的所有类和它实现的接口。 这些可以存储在散列集中,给出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 

我明白了

 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) 

表现是一样的。

我不知道如何处理它,但你可以通过查看JIT编译器的源代码,或者通过转储JIT编译的本机代码来查找一些示例。

如何处理类加载? 加载新的子类意味着必须调整很多间隔。

在某些情况下,JIT编译器会根据当前所有已加载类集合的假设进行优化。 如果加载了新类,我理解编译器将受影响的JIT编译类标记为需要重新编译。