instanceof和Class.isAssignableFrom(...)有什么区别?
以下哪项更好?
a instanceof B
要么
B.class.isAssignableFrom(a.getClass())
我所知道的唯一区别是,当'a'为空时,第一个返回false,第二个抛出异常。 除此之外,他们总是给出相同的结果吗?
使用instanceof
,您需要在编译时了解B
的类。 当使用isAssignableFrom()
它可以是动态的,并在运行时更改。
instanceof
只能用于引用类型,而不能用于基本类型。 isAssignableFrom()
可以用于任何类对象:
a instanceof int // syntax error
3 instanceof Foo // syntax error
int.class.isAssignableFrom(int.class) // true
请参阅http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class)。
就性能而言:
TL; DR
使用具有相似性能的isInstance或instanceof 。 isAssignableFrom稍微慢一些。
按性能排序:
基于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);
测量每个运算符使用多少字节码指令,我们可以预期instanceof和isInstance比isAssignableFrom快。 但是,实际的性能不是由字节码决定的,而是由机器码决定的(与平台相关)。 让我们为每个运营商做一个微观基准。
基准
信用:正如@ aleksandr-dubinsky所建议的,并感谢@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
警告
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 < 100; ++i)
execute();
// Time it
int count = 100000;
final long start = System.nanoTime();
for(int i=0; i<count; i++){
execute();
}
final long elapsed = System.nanoTime() - start;
感谢JIT,代码在某个时候进行了优化,我们得到:
注意
最初这篇文章是使用原始JAVA中的for循环做自己的基准测试,由于像Just In Time这样的一些优化可以消除循环,所以给出了不可靠的结果。 所以它主要测量JIT编译器花费多少时间来优化循环:请参阅独立于迭代次数的性能测试以了解更多详细信息
相关问题
上一篇: What is the difference between instanceof and Class.isAssignableFrom(...)?