以下哪项更好?
a instanceof B
要么
B.class.isAssignableFrom(a.getClass())
我所知道的唯一区别是,当'a'为null时,第一个返回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略慢.
按性能排序:
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
警告
该基准测试依赖于JVM和平台.由于每个操作之间没有显着差异,因此可能在不同的JAVA版本和/或Solaris,Mac或Linux等平台上获得不同的结果(可能是不同的顺序!).
基准比较直接"B扩展A"时"是B实例"的性能.如果类层次结构更深且更复杂(如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 < 100; ++i) execute(); // Time it int count = 100000; final long start = System.nanoTime(); for(int i=0; i感谢JIT,代码在某些时候进行了优化,我们得到:
instanceof:6ms
isInstance:12ms
isAssignable来自:15ms
注意
最初这篇文章是在原始JAVA中使用for循环进行自己的基准测试,由于像Just In Time这样的优化可以消除循环,因此产生了不可靠的结果.因此,它主要测量JIT编译器优化循环所需的时间:请参阅性能测试,与迭代次数无关,以获取更多详细信息
相关问题
instanceof运算符是否会产生大量开销?为什么?
如何在JAVA中实现instanceof?
在Java中使用instanceof的性能影响
是的,`instanceof`是一个字节码,它使用与`checkcast`(铸造背后的字节码)基本相同的逻辑.无论JITC优化程度如何,它本身都会比其他选项更快.
不要编写自己的微基准测试!使用JMH.
4> user102008..:更直接的相当于
a instanceof B
是B.class.isInstance(a)当此作品(返回false)
a
是null
也.
5> 小智..:除了上面提到的基本差异之外,instanceof运算符和Class中的isAssignableFrom方法之间存在核心细微差别.
读
instanceof
为"这是(左侧部分)这个或其任何子类(右侧部分)的实例"并读x.getClass().isAssignableFrom(Y.class)
作"我可以写X x = new Y()
".换句话说,instanceof运算符检查左对象是否是右类的相同或子类,同时isAssignableFrom
检查我们是否可以将参数类(from)的对象分配给调用该方法的类的引用.
请注意,这两个都认为实际的实例不是引用类型.考虑3个类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.
`b instanceof A`相当于`A.class.isAssignableFrom(b.getClass())`(正如OP注意到的那样).你的例子是正确但无关紧要的.
为什么在此示例中为“ b.getClass()。isAssignableFrom(A.class)”?我猜例子应该是反向的A.class.isAssignableFrom(b.getClass())。
6> 小智..:还有另一个区别:
null instanceof X
false
无论X是什么null.getClass().isAssignableFrom(X)将抛出NullPointerException
-1,不正确:`null instanceof X`(其中X是编译时已知的某个类)将始终返回`false`.
@Caspar虽然你是对的,但基本的想法是个好点.我编辑了帖子,这是正确的.
7> 小智..:还有另一个不同之处.如果要测试的类型(Class)是动态的,例如作为方法参数传递,那么instanceof将不会为您剪切它.
boolean test(Class clazz) { return (this instanceof clazz); // clazz cannot be resolved to a type. }但你可以这样做:
boolean test(Class clazz) { return (clazz.isAssignableFrom(this.getClass())); // okidoki }哎呀,我看到这个答案已经涵盖了.也许这个例子对某人有帮助.
实际上没有答案是真的正确isAssignableFrom工作w /类,Class.isInstance是*'instanceof'的模拟*
8> 小智..:这个主题为我提供了一些
instanceof
有所不同的见解isAssignableFrom
,所以我想我会分享一些自己的东西.我发现
isAssignableFrom
如果一个类的引用可以接受另一个类的实例,当一个类没有类的实例进行比较时,使用它是唯一的(可能不是唯一的,但可能是最简单的)方式来询问自己.因此,我没有发现使用
instanceof
运算符来比较赋值是一个好主意,当我所有的都是类时,除非我考虑从其中一个类创建一个实例; 我以为这会马虎.
9> James Drinka..:instanceof不能与基本类型或泛型类型一起使用。如以下代码所示:
//Define Class< T > type ... Object e = new Object(); if(e instanceof T) { // Do something. }错误是:无法对类型参数T执行instanceof检查。请改用它的擦除对象,因为在运行时将删除更多的通用类型信息。
由于类型删除导致无法编译,因此删除了运行时引用。但是,下面的代码将编译:
if( type.isAssignableFrom(e.getClass())){ // Do something. }