Java instanceof 和 Class.isAssignableFrom(...) 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/496928/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between instanceof and Class.isAssignableFrom(...)?
提问by Megamug
Which of the following is better?
以下哪个更好?
a instanceof B
or
或者
B.class.isAssignableFrom(a.getClass())
The only difference that I know of is, when 'a' is null, the first returns false, while the second throws an exception. Other than that, do they always give the same result?
我所知道的唯一区别是,当 'a' 为空时,第一个返回 false,而第二个抛出异常。除此之外,他们总是给出相同的结果吗?
采纳答案by Marc Novakowski
When using instanceof
, you need to know the class of B
at compile time. When using isAssignableFrom()
it can be dynamic and change during runtime.
使用时instanceof
,需要B
在编译时知道类。使用时isAssignableFrom()
它可以是动态的,并在运行时发生变化。
回答by Adam Rosenfield
instanceof
can only be used with reference types, not primitive types. isAssignableFrom()
can be used with any class objects:
instanceof
只能用于引用类型,不能用于原始类型。 isAssignableFrom()
可以与任何类对象一起使用:
a instanceof int // syntax error
3 instanceof Foo // syntax error
int.class.isAssignableFrom(int.class) // true
See http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class).
看 http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class)。
回答by algebra
Consider following situation. Suppose you want to check whether type A is a super class of the type of obj, you can go either
考虑以下情况。假设你要检查类型A是否是obj类型的超类,你可以去
... A.class.isAssignableFrom(obj.getClass()) ...
... A.class.isAssignableFrom(obj.getClass()) ...
OR
或者
... obj instanceof A ...
... obj instanceof A ...
But the isAssignableFrom solution requires that the type of obj be visible here. If this is not the case (e.g., the type of obj might be of a private inner class), this option is out. However, the instanceof solution would always work.
但是 isAssignableFrom 解决方案要求 obj 的类型在这里可见。如果不是这种情况(例如,obj 的类型可能是私有内部类),则此选项无效。但是,instanceof 解决方案始终有效。
回答by Milan
some tests we did in our team show that A.class.isAssignableFrom(B.getClass())
works faster than B instanceof A
. this can be very useful if you need to check this on large number of elements.
我们在团队中进行的一些测试表明,它A.class.isAssignableFrom(B.getClass())
比B instanceof A
. 如果您需要对大量元素进行检查,这将非常有用。
回答by Ashish Arya
Apart from basic differences mentioned above, there is a core subtle difference between instanceof operator and isAssignableFrom method in Class.
除了上面提到的基本差异之外,实例化运算符和类中的 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.
读instanceof
作“这是(左侧部分)this 的实例还是 this 的任何子类(右侧部分)”,读x.getClass().isAssignableFrom(Y.class)
作“我可以写吗X x = new Y()
”。换句话说, instanceof 运算符检查左对象是否相同或右类的子类,同时isAssignableFrom
检查我们是否可以将参数类(from)的对象分配给调用该方法的类的引用。
请注意,这两者都考虑实际实例而不是引用类型。
Consider an example of 3 classes A, B and C where C extends B and B extends A.
考虑 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.
回答by S. Ali Tokmen
There is also another difference:
还有一个区别:
null instanceof X is false
no matter what X is
null instanceof X 是false
不管 X 是什么
null.getClass().isAssignableFrom(X) will throw a NullPointerException
null.getClass().isAssignableFrom(X) 将抛出 NullPointerException
回答by tkalmijn
There is yet another difference. If the type (Class) to test against is dynamic, e.g. passed as a method parameter, then instanceof won't cut it for you.
还有另一个区别。如果要测试的类型 (Class) 是动态的,例如作为方法参数传递,则 instanceof 不会为您剪切。
boolean test(Class clazz) {
return (this instanceof clazz); // clazz cannot be resolved to a type.
}
but you can do:
但你可以这样做:
boolean test(Class clazz) {
return (clazz.isAssignableFrom(this.getClass())); // okidoki
}
Oops, I see this answer is already covered. Maybe this example is helpful to someone.
哎呀,我看到这个答案已经涵盖了。也许这个例子对某人有帮助。
回答by user102008
A more direct equivalent to a instanceof B
is
更直接等同于a instanceof B
IS
B.class.isInstance(a)
This works (returns false) when a
is null
too.
该作品(返回false)时a
是null
也。
回答by Owen
This thread provided me some insight into how instanceof
differed from isAssignableFrom
, so I thought I'd share something of my own.
这个帖子让我深入了解了instanceof
与 的不同之处isAssignableFrom
,所以我想我会分享一些我自己的东西。
I have found that using isAssignableFrom
to be the only (probably not the only, but possibly the easiest) way to ask one's self if a reference of one class can take instances of another, when one has instances of neither class to do the comparison.
我发现曾经isAssignableFrom
是唯一的(可能不是唯一的,但可能是最简单的)询问自己一个类的引用是否可以引用另一个类的实例的方法,当一个类的实例没有进行比较时。
Hence, I didn't find using the instanceof
operator to compare assignability to be a good idea when all I had were classes, unless I contemplated creating an instance from one of the classes; I thought this would be sloppy.
因此,instanceof
当我只有类时,我没有发现使用运算符来比较可分配性是一个好主意,除非我考虑从其中一个类创建一个实例;我以为这会很草率。
回答by JBE
Talking in terms of performance :
谈性能:
TL;DR
TL; 博士
Use isInstanceor instanceofwhich have similar performance. isAssignableFromis slightly slower.
使用具有相似性能的isInstance或instanceof。isAssignableFrom稍慢。
Sorted by performance:
按性能排序:
- isInstance
- instanceof(+ 0.5%)
- isAssignableFrom(+ 2.7%)
- isInstance
- 实例(+ 0.5%)
- isAssignableFrom(+ 2.7%)
Based on a benchmark of 2000 iterations on JAVA 8 Windows x64, with 20 warmup iterations.
基于在 JAVA 8 Windows x64 上进行 2000 次迭代的基准测试,其中包含 20 次预热迭代。
In theory
理论上
Using a soft like bytecode viewerwe can translate each operator into bytecode.
使用像字节码查看器这样的软件,我们可以将每个运算符转换为字节码。
In the context of:
在以下情况下:
package foo;
public class Benchmark
{
public static final Object a = new A();
public static final Object b = new B();
...
}
JAVA:
爪哇:
b instanceof A;
Bytecode:
字节码:
getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A
JAVA:
爪哇:
A.class.isInstance(b);
Bytecode:
字节码:
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());
Bytecode:
字节码:
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);
Measuring how many bytecode instructions are used by each operator, we could expect instanceofand isInstanceto be faster than isAssignableFrom. However, the actual performance is NOT determined by the bytecode but by the machine code (which is platform dependent). Let's do a micro benchmark for each of the operators.
测量每个运算符使用多少字节码指令,我们可以预期instanceof和isInstance比isAssignableFrom更快。但是,实际性能不是由字节码决定的,而是由机器代码(取决于平台)决定的。让我们为每个运营商做一个微基准测试。
The benchmark
基准
Credit: As advised by @aleksandr-dubinsky, and thanks to @yura for providing the base code, here is a JMHbenchmark (see this tuning guide):
信用:根据@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();
}
}
Gave the following results (score is a number of operations in a time unit, so the higher the score the better):
给出如下结果(分数是一个时间单位内的操作次数,所以分数越高越好):
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
Warning
警告
- 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 anisInstance
for example...
- 基准是 JVM 和平台相关的。由于每个操作之间没有显着差异,因此在不同的 JAVA 版本和/或平台(如 Solaris、Mac 或 Linux)上可能会得到不同的结果(可能还有不同的顺序!)。
- 该基准比较了“B 直接扩展 A”时“是 B 是 A 的实例”的性能。如果类层次结构更深更复杂(如 B 扩展 X 扩展 Y 扩展 Z 扩展 A),结果可能会有所不同。
- 通常建议先选择一个运算符(最方便)编写代码,然后分析您的代码以检查是否存在性能瓶颈。也许这个运算符在你的代码上下文中可以忽略不计,或者......
- 关于上一点,
instanceof
在您的代码上下文中可能比例isInstance
如...
To give you an example, take the following loop:
举个例子,请看下面的循环:
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;
Thanks to the JIT, the code is optimized at some point and we get:
多亏了 JIT,代码在某个时候得到了优化,我们得到:
- instanceof: 6ms
- isInstance: 12ms
- isAssignableFrom : 15ms
- 实例:6ms
- isInstance:12ms
- isAssignableFrom : 15ms
Note
笔记
Originally this post was doing its own benchmark using a forloop in raw JAVA, which gave unreliable results as some optimization like Just In Time can eliminate the loop. So it was mostly measuring how long did the JIT compiler take to optimize the loop: see Performance test independent of the number of iterationsfor more details
最初,这篇文章是在原始 JAVA 中使用for循环进行自己的基准测试,结果不可靠,因为像 Just In Time 这样的优化可以消除循环。所以它主要是测量 JIT 编译器优化循环需要多长时间:有关更多详细信息,请参阅与迭代次数无关的性能测试
Related questions
相关问题