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. Other than that, do they always give the same result?


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 can only be used with reference types, not primitive types. isAssignableFrom() can be used with any class objects:

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).


Talking in terms of performance :

TL;DR

Use isInstance or instanceof which have similar performance. isAssignableFrom is slightly slower.

Sorted by performance:

  • isInstance
  • instanceof (+ 0.5%)
  • isAssignableFrom (+ 2.7%)
  • Based on a benchmark of 2000 iterations on JAVA 8 Windows x64, with 20 warmup iterations.

    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:

    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 is used by each operator, we could expect instanceof and isInstance to 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 operator.

    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):

    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 is 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 platform 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 operator (the most convenient) and then profile your code to check if there are performance bottleneck. Maybe this operator is negligible in the context of your code, or maybe...
  • in relation to previous point, instanceof in the context of your code might get optimized more easily than an isInstance for example...
  • 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:

  • instanceof: 6ms
  • isInstance: 12ms
  • isAssignableFrom : 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. 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

    Related questions

  • Does instanceof operator generate a lot of overhead ? Why?
  • How instanceof is implemented inside JAVA?
  • The performance impact of using instanceof in Java
  • 链接地址: http://www.djcxy.com/p/13328.html

    上一篇: 如何检查Java中是否存在文件?

    下一篇: instanceof和Class.isAssignableFrom(...)有什么区别?