就表演而言:
TL;DR
使用isInstance或例有相似的表现。从稍微慢一点。
按性能排序:isInstance
例 (+ 0.5%)
从 (+ 2.7%)
基于Java 8 Windows x64上2000次迭代的基准,有20次热身迭代。
理论上
使用软的字节码查看器我们可以将每个操作符转换为字节码。
在以下方面:package foo;
public class Benchmark
{
public static final Object a = new A();
public static final Object b = new B();
...
}
Java:b instanceof A;
字节码:getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A
Java:A.class.isInstance(b);
字节码:ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Class isInstance((Ljava/lang/Object;)Z);
Java:A.class.isAssignableFrom(b.getClass());
字节码:ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Object getClass(()Ljava/lang/Class;);
invokevirtual java/lang/Class isAssignableFrom((Ljava/lang/Class;)Z);
测量每个操作符使用多少字节码指令,我们可以预期。例和isInstance比从..但是,实际性能不是由字节码决定的,而是由机器代码(与平台有关)决定的。让我们为每个操作符做一个微基准。
基准
信用:正如@Aleksandr-duinsky所建议的,感谢@yura提供了基本代码,下面是一个JMH基准(参见调谐导轨):class A {}
class B extends A {}
public class Benchmark {
public static final Object a = new A();
public static final Object b = new B();
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testInstanceOf()
{
return b instanceof A;
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testIsInstance()
{
return A.class.isInstance(b);
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testIsAssignableFrom()
{
return A.class.isAssignableFrom(b.getClass());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(TestPerf2.class.getSimpleName())
.warmupIterations(20)
.measurementIterations(2000)
.forks(1)
.build();
new Runner(opt).run();
}
}
给出了以下结果(分数为一个时间单位中的许多操作,所以分数越高越好):Benchmark Mode Cnt Score Error Units
Benchmark.testIsInstance thrpt 2000 373,061 ± 0,115 ops/us
Benchmark.testInstanceOf thrpt 2000 371,047 ± 0,131 ops/us
Benchmark.testIsAssignableFrom thrpt 2000 363,648 ± 0,289 ops/us
警告基准测试是JVM和平台依赖的。由于每个操作之间没有显着性差异,所以可能会得到不同的结果(也可能是不同的顺序!)在不同的Java版本和/或平台上,如Solaris、Mac或Linux。
当“B直接扩展A”时,基准比较了“isB是A的一个实例”的性能。如果类层次更深、更复杂(如B扩展X,扩展Y,扩展Z,扩展A),则结果可能不同。
通常建议首先编写代码,选择一个操作符(最方便),然后分析代码,以检查是否存在性能瓶颈。也许这个操作符在你的代码中是可以忽略不计的,或者.
关于前一点,
instanceof在您的代码上下文中,可能比
isInstance例如.。
为了给出一个例子,请使用下面的循环:class A{}
class B extends A{}
A b = new B();
boolean execute(){
return A.class.isAssignableFrom(b.getClass());
// return A.class.isInstance(b);
// return b instanceof A;
}
// Warmup the code
for (int i = 0; i
execute();
// Time it
int count = 100000;
final long start = System.nanoTime();
for(int i=0; i
execute();
}
final long elapsed = System.nanoTime() - start;
由于有了JIT,代码在某种程度上得到了优化,我们得到:实例:6ms
isInstance:12 ms
来自:15 ms
注
最初,这篇文章使用一个为循环在原始Java中,这给出了不可靠的结果,因为有些优化就像在时间上一样,可以消除循环。因此,它主要是测量JIT编译器对循环进行优化所花费的时间:独立于迭代次数的性能测试想了解更多细节
相关问题