现代JVM实现中如何实现instanceof操作?

3
由于在其他线程中进行了基准测试(参见https://dev59.com/m3VD5IYBdhLWcg3wDXJ3#397617),显示Java 6中的instanceof实际上非常快速。这是如何实现的?
我知道对于单继承,最快的想法是使用一些嵌套的区间编码,其中每个类维护一个[low,high]区间,并且instanceof仅是一个区间包含测试,即2个整数比较。但是如何为接口实现此功能(因为区间包含仅适用于单继承)?类加载如何处理?加载新的子类意味着必须调整许多区间。
1个回答

6
据我所知,每个类都知道它所扩展的所有类和它实现的接口。这些可以存储在哈希集合中,以实现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

如果我将“doubles”更改为
    for(int i=0;i<doubles.length;i+=2)
        doubles[i] = "";

I get

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)

to

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

性能没有变化。


我也在考虑使用哈希表方法。但有些情况下,instanceof 比哈希表查找更快。它甚至比不带参数的单个函数调用还要快。 - gexicide
生成的代码可以内联。对于上面的Double情况,由于该类是final,因此测试与d != null && d.getClass() == Double.class相同。 - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接