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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:23:10  来源:igfitidea点击:

What is the difference between instanceof and Class.isAssignableFrom(...)?

javainstanceofreflection

提问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 Bat compile time. When using isAssignableFrom()it can be dynamic and change during runtime.

使用时instanceof,需要B在编译时知道类。使用时isAssignableFrom()它可以是动态的,并在运行时发生变化。

回答by Adam Rosenfield

instanceofcan 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 instanceofas “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 isAssignableFromchecks 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 falseno 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 Bis

更直接等同于a instanceof BIS

B.class.isInstance(a)

This works (returns false) when ais nulltoo.

该作品(返回false)时anull也。

回答by Owen

This thread provided me some insight into how instanceofdiffered from isAssignableFrom, so I thought I'd share something of my own.

这个帖子让我深入了解了instanceof与 的不同之处isAssignableFrom,所以我想我会分享一些我自己的东西。

I have found that using isAssignableFromto 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 instanceofoperator 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.

使用具有相似性能的isInstanceinstanceofisAssignableFrom稍慢。

Sorted by performance:

按性能排序:

  1. isInstance
  2. instanceof(+ 0.5%)
  3. isAssignableFrom(+ 2.7%)
  1. isInstance
  2. 实例(+ 0.5%)
  3. 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.

测量每个运算符使用多少字节码指令,我们可以预期instanceofisInstanceisAssignableFrom更快。但是,实际性能不是由字节码决定的,而是由机器代码(取决于平台)决定的。让我们为每个运营商做一个微基准测试。

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, instanceofin the context of your code might get optimized more easily than an isInstancefor 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

相关问题