下面哪个比较好?
a instanceof B
or
B.class.isAssignableFrom(a.getClass())
我所知道的唯一区别是,当'a'为空时,第一个返回false,而第二个抛出异常。除此之外,它们总是给出相同的结果吗?
下面哪个比较好?
a instanceof B
or
B.class.isAssignableFrom(a.getClass())
我所知道的唯一区别是,当'a'为空时,第一个返回false,而第二个抛出异常。除此之外,它们总是给出相同的结果吗?
当前回答
这个帖子让我了解了instanceof与isAssignableFrom的不同之处,所以我想分享一下我自己的一些内容。
我发现使用isAssignableFrom是唯一的(可能不是唯一的,但可能是最简单的)方法来询问自己一个类的引用是否可以接受另一个类的实例,当一个类的实例都没有时进行比较。
因此,当我只有类时,我不认为使用instanceof操作符比较可赋值性是一个好主意,除非我打算从其中一个类创建一个实例;我觉得这样会很草率。
其他回答
我们在团队中做的一些测试表明,A.class. isassignablefrom (B. getclass())比B instanceof a工作得更快,如果你需要对大量元素进行检查,这是非常有用的。
在性能“2”方面(与JMH):
class A{}
class B extends A{}
public class InstanceOfTest {
public static final Object a = new A();
public static final Object b = new B();
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testInstanceOf()
{
return b instanceof A;
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testIsInstance()
{
return A.class.isInstance(b);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testIsAssignableFrom()
{
return A.class.isAssignableFrom(b.getClass());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(InstanceOfTest.class.getSimpleName())
.warmupIterations(5)
.measurementIterations(5)
.forks(1)
.build();
new Runner(opt).run();
}
}
它给:
Benchmark Mode Cnt Score Error Units
InstanceOfTest.testInstanceOf avgt 5 1,972 ? 0,002 ns/op
InstanceOfTest.testIsAssignableFrom avgt 5 1,991 ? 0,004 ns/op
InstanceOfTest.testIsInstance avgt 5 1,972 ? 0,003 ns/op
因此,我们可以得出结论:instanceof as fast as isInstance() and isAssignableFrom() not far(+0.9%的执行时间)。所以无论你选择什么都没有真正的区别
谈论业绩:
博士TL;
请使用性能相似的isInstance或instanceof。isAssignableFrom稍微慢一点。
按性能排序:
isInstance Instanceof (+ 0.5%) isAssignableFrom (+ 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);
测量每个操作符使用了多少字节码指令,我们可以期望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
警告
the benchmark is JVM and platform dependent. Since there are no significant differences between each operation, it might be possible to get a different result (and maybe different order!) on a different JAVA version and/or platforms like Solaris, Mac or Linux. the benchmark compares the performance of "is B an instance of A" when "B extends A" directly. If the class hierarchy is deeper and more complex (like B extends X which extends Y which extends Z which extends A), results might be different. it is usually advised to write the code first picking one of the operators (the most convenient) and then profile your code to check if there are a performance bottleneck. Maybe this operator is negligible in the context of your code, or maybe... in relation to the previous point, instanceof in the context of your code might get optimized more easily than an isInstance for example...
给你一个例子,看下面的循环:
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,代码在某些时候被优化了,我们得到:
运算符:6女士 女士isInstance: 12 isAssignableFrom: 15毫秒
Note
最初这篇文章是在原始JAVA中使用for循环进行自己的基准测试,这给出了不可靠的结果,因为一些优化如Just in Time可以消除循环。因此主要是衡量JIT编译器优化循环所花费的时间:有关更多细节,请参阅与迭代次数无关的性能测试
相关问题
instanceof操作符是否产生大量开销?为什么? instanceof是如何在JAVA中实现的? 在Java中使用instanceof对性能的影响
Instanceof也不能用于基本类型或泛型类型。如下代码所示:
//Define Class< T > type ...
Object e = new Object();
if(e instanceof T) {
// Do something.
}
错误是:不能对类型参数t执行instanceof检查,而是使用它的erasure对象,因为进一步的泛型类型信息将在运行时被擦除。
由于删除运行时引用的类型擦除而无法编译。然而,下面的代码将编译:
if( type.isAssignableFrom(e.getClass())){
// Do something.
}
在使用instanceof时,您需要在编译时知道B的类。当使用isAssignableFrom()时,它可以是动态的,并在运行时更改。