下面哪个比较好?
a instanceof B
or
B.class.isAssignableFrom(a.getClass())
我所知道的唯一区别是,当'a'为空时,第一个返回false,而第二个抛出异常。除此之外,它们总是给出相同的结果吗?
下面哪个比较好?
a instanceof B
or
B.class.isAssignableFrom(a.getClass())
我所知道的唯一区别是,当'a'为空时,第一个返回false,而第二个抛出异常。除此之外,它们总是给出相同的结果吗?
当前回答
这完全取决于代码中此时可用的内容。我不建议使用isAssignableFrom如果你正在使用一个实际的对象-有一个更好的选择。下面是一份根据你所拥有的产品进行排名的推荐列表:
如果你有一个对象a,并且你在编译时知道类型B: a instanceof实例 如果你有一个对象a,你不知道类型B,但你有一个对象B: .isInstance b.getClass () () 如果你有一个对象a,在编译时没有类型或实例化对象,但你有一个类对象class <?> someBClass: someBClass.isInstance (a) 如果你没有实例化对象,但是你有两个Class<?>对象: someBClass.isAssignableFrom (someAClass)。
假设你从列表的顶部开始,然后往下做,每一种方法都是实现目标的最简单的方法,根据我自己的研究,我相信你也会得到最好的表现。
其他回答
这完全取决于代码中此时可用的内容。我不建议使用isAssignableFrom如果你正在使用一个实际的对象-有一个更好的选择。下面是一份根据你所拥有的产品进行排名的推荐列表:
如果你有一个对象a,并且你在编译时知道类型B: a instanceof实例 如果你有一个对象a,你不知道类型B,但你有一个对象B: .isInstance b.getClass () () 如果你有一个对象a,在编译时没有类型或实例化对象,但你有一个类对象class <?> someBClass: someBClass.isInstance (a) 如果你没有实例化对象,但是你有两个Class<?>对象: someBClass.isAssignableFrom (someAClass)。
假设你从列表的顶部开始,然后往下做,每一种方法都是实现目标的最简单的方法,根据我自己的研究,我相信你也会得到最好的表现。
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 (. lang . class)。
除了上面提到的基本区别之外,在类中的instanceof操作符和isAssignableFrom方法之间还有一个核心的微妙区别。
Read instanceof as “is this (the left part) the instance of this or any subclass of this (the right part)” and read x.getClass().isAssignableFrom(Y.class) as “Can I write X x = new Y()”. In other words, instanceof operator checks if the left object is same or subclass of right class, while isAssignableFrom checks if we can assign object of the parameter class (from) to the reference of the class on which the method is called. Note that both of these consider the actual instance not the reference type.
考虑一个A、B和C三个类的例子,其中C扩展了B, B扩展了A。
B b = new C();
System.out.println(b instanceof A); //is b (which is actually class C object) instance of A, yes. This will return true.
System.out.println(b instanceof B); // is b (which is actually class C object) instance of B, yes. This will return true.
System.out.println(b instanceof C); // is b (which is actually class C object) instance of C, yes. This will return true. If the first statement would be B b = new B(), this would have been false.
System.out.println(b.getClass().isAssignableFrom(A.class));//Can I write C c = new A(), no. So this is false.
System.out.println(b.getClass().isAssignableFrom(B.class)); //Can I write C c = new B(), no. So this is false.
System.out.println(b.getClass().isAssignableFrom(C.class)); //Can I write C c = new C(), Yes. So this is true.
我们在团队中做的一些测试表明,A.class. isassignablefrom (B. getclass())比B instanceof a工作得更快,如果你需要对大量元素进行检查,这是非常有用的。
谈论业绩:
博士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对性能的影响