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

时间:2012-09-12 11:07:57

标签: java jvm implementation instanceof

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

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

2 个答案:

答案 0 :(得分:5)

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<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)

表现相同。

答案 1 :(得分:0)

我不知道如何处理这个问题,但你可以通过查看JIT编译器的源代码,或者通过转储JIT编译的本机代码来查找。

  

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

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