instanceof和Class.isAssignableFrom(...)有什么区别?

本文翻译自:What is the difference between instanceof and Class.isAssignableFrom(…)?

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. 我所知道的唯一区别是,当'a'为null时,第一个返回false,而第二个抛出异常。 Other than that, do they always give the same result? 除此之外,他们总是给出相同的结果吗?


#1楼

参考:https://stackoom.com/question/25Gy/instanceof和Class-isAssignableFrom-有什么区别


#2楼

Talking in terms of performance : 谈论绩效:

TL;DR TL; DR

Use isInstance or instanceof which have similar performance. 使用具有类似性能的isInstanceinstanceof isAssignableFrom is slightly slower. isAssignableFrom略慢。

Sorted by performance: 按性能排序:

  1. isInstance isInstance
  2. instanceof (+ 0.5%) instanceof (+ 0.5%)
  3. isAssignableFrom (+ 2.7%) 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 viewer we 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: JAVA:

b instanceof A;

Bytecode: 字节码:

getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A

JAVA: 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: 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 instanceof and isInstance to be faster than isAssignableFrom . 测量每个运算符使用的字节码指令的数量,我们可以预期instanceofisInstanceisAssignableFrom更快。 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. 让我们为每个运营商做一个微基准测试。

The benchmark 基准

Credit: As advised by @aleksandr-dubinsky, and thanks to @yura for providing the base code, here is a JMH benchmark (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. 该基准测试依赖于JVM和平台。 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. 由于每个操作之间没有显着差异,因此可能在不同的JAVA版本和/或Solaris,Mac或Linux等平台上获得不同的结果(可能是不同的顺序!)。
  • the benchmark compares the performance of "is B an instance of A" when "B extends A" directly. 基准比较直接“B扩展A”时“是B实例”的性能。 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. 如果类层次结构更深且更复杂(如B扩展X扩展Y,扩展Z扩展A),结果可能不同。
  • 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... 与前一点相关,代码上下文中的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 instanceof:6ms
  • isInstance: 12ms isInstance:12ms
  • isAssignableFrom : 15ms isAssignable来自:15ms

Note 注意

Originally this post was doing its own benchmark using a for loop in raw JAVA, which gave unreliable results as some optimization like Just In Time can eliminate the loop. 最初这篇文章是在原始JAVA中使用for循环进行自己的基准测试,由于像Just In Time这样的优化可以消除循环,因此产生了不可靠的结果。 So it was mostly measuring how long did the JIT compiler take to optimize the loop: see Performance test independent of the number of iterations for more details 因此,它主要测量JIT编译器优化循环所需的时间:请参阅性能测试,与迭代次数无关,以获取更多详细信息

Related questions 相关问题


#3楼

instanceof cannot be used with primitive types or generic types either. instanceof也不能与基本类型或泛型类型一起使用。 As in the following code: 如下面的代码所示:

//Define Class< T > type ... 

Object e = new Object();

if(e instanceof T) {
  // Do something.
}

The error is: Cannot perform instanceof check against type parameter T. Use it's erasure Object instead since further generic type information will be erased at runtime. 错误是:无法对类型参数T执行instanceof检查。使用它的擦除对象,因为将在运行时擦除其他泛型类型信息。

Does not compile due to type erasure removing the runtime reference. 由于类型擦除删除运行时引用而无法编译。 However, the code below will compile: 但是,下面的代码将编译:

if( type.isAssignableFrom(e.getClass())){
  // Do something.
}

#4楼

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. 但isAssignableFrom解决方案要求obj的类型在这里可见。 If this is not the case (eg, the type of obj might be of a private inner class), this option is out. 如果不是这种情况(例如,obj的类型可能是私有内部类),则此选项不存在。 However, the instanceof solution would always work. 但是,解决方案的实例始终有效。


#5楼

some tests we did in our team show that A.class.isAssignableFrom(B.getClass()) works faster than B instanceof A . 我们在团队中进行的一些测试表明, A.class.isAssignableFrom(B.getClass())工作速度比B instanceof A快。 this can be very useful if you need to check this on large number of elements. 如果您需要在大量元素上进行检查,这可能非常有用。


#6楼

isAssignableFrom(A, B) =

if (A == B) return true
else if (B == java.lang.Object) return false
else return isAssignableFrom(A, getSuperClass(B))

The pseudo code above is a definition of, if references of type/class A is assignable from references of type/class B. It is a recursive definition. 如果类型/类A的引用可以从类型/类B的引用分配,则上面的伪代码是定义。它是递归定义。 To some it may be helpful, for others it may be confusing. 对某些人来说,这可能会有所帮助,对于其 I add it in case somebody should find it useful. 我添加它以防有人应该发现它有用。 This is just an attempt to capture my understanding, it is not the official definition. 这只是为了捕捉我的理解,它不是官方的定义。 It is used in a certain Java VM implementation and works for many example programs, so while I cannot guarentee that it captures all aspects of isAssignableFrom, it is not completely off. 它用于某个Java VM实现并适用于许多示例程序,因此虽然我不能保证它捕获了isAssignableFrom的所有方面,但它并没有完全关闭。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值