513

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?

2
  • 17
    For the records, isInstance() is the most convenient method to check whether an object can be casted into a class type (for more details, see: tshikatshikaaa.blogspot.nl/2012/07/…) Commented Jul 29, 2012 at 20:15
  • 2
    To counter what @JérômeVerstrynge suggested: The instanceof construction is a preferred way to check whether a variable can be cast to some type statically because a compile-time error will occur in case of incompatible types. The method isInstance() from java.lang.Class works differently and does type check at runtime only, incompatible types will therefore not be detected early in the development, potentially resulting in dead code. The isInstance() method should only be used in dynamic cases when the instanceof operator can’t be used. Commented Nov 23, 2021 at 13:46

16 Answers 16

559

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.

Sign up to request clarification or add additional context in comments.

9 Comments

i don't get it - please elaborate on why we can't write a instanceof Bref.getClass(). how can this be the accepted answer with so little explanation (or its lack thereof)?
The syntax is a instanceof Bref not a instanceof Bref.class. The second argument to the instanceof operator is a class name, not an expression resolving to a class object instance.
yes "dynamic" goes without saying :) Other than performance, this is a true difference.
@EliranMalka maybe you can have a class that was generated in runtime. Like proxies objects.
If you have an object a and you know the type B at compile type, use a instanceof B. If you have a and you don't know the type B but you have an object b, use b.getClass().isInstance(a). If you have a and you don't have an object but rather a Class<?> someBClass, use someBClass.isInstance(a). If you have two Class<?> but no actual instantiated objects of the types, that one condition is when you use someBClass.isAssignableFrom(someAClass).
This comment should be the accepted answer. It explains the crypted answer of Marc Novakowski and expand it too.
|
224

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

2 Comments

I don't see the point of using instanceof/isAssignableFrom with primitive types.
Adam was just proving the point...
124

Talking in terms of performance :

TL;DR

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

Sorted by performance:

  1. isInstance
  2. instanceof (+ 0.5%)
  3. 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 are 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 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):

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

4 Comments

Yep, instanceof is a bytecode that uses essentially the same logic as checkcast (the bytecode behind casting). It will inherently be faster than the other options, regardless of degree of JITC optimization.
Which makes sense, as isAssignableFrom() is dynamic.
yep, with JMH results are completely different (same speed for all).
Hi, nice benchmark, just ran into a situation where isAssignableFrom was called thousands of times, changing to instanceof really made a difference. This reply would be worth a blog post somewhere... ;)
36

A more direct equivalent to a instanceof B is

B.class.isInstance(a) 

This works (returns false) when a is null too.

1 Comment

Cool, but this doesn't answer the question and should have been a comment.
31

Apart from basic differences mentioned above, there is a core subtle difference between instanceof operator and isAssignableFrom method in Class.

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.

Consider an example of 3 classes A, B and C where C extends B and B extends 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. 

4 Comments

b instanceof A is equivalent to A.class.isAssignableFrom(b.getClass()) (as the OP noticed). Your example is correct but irrelevant.
Since new Y() may not be legal if Y is abstract or without public default constructor, you can say X x = (Y)null is legal if and only if x.getClass().isAssignableFrom(Y.class) is true.
Why 'b.getClass().isAssignableFrom(A.class)' in this example? I guess example should be reverse A.class.isAssignableFrom(b.getClass()).
sorry but this answer is incorrect for this question and can mislead readers: the question is explicitly making the examples a instanceof B and B.class.isAssignableFrom(a.getClass()) In your answer you have swapped them in the second expression.
14

There is also another difference:

null instanceof X is false no matter what X is

null.getClass().isAssignableFrom(X) will throw a NullPointerException

5 Comments

-1, incorrect: null instanceof X (where X is some class known at compile time) will always return false.
@Caspar while you are correct, the basic idea was a good point. I edited the post so that it is correct.
this is helpful, the edge case is always important :).
To be equivalent to the first line, the second line should be X.class.isAssignableFrom(null.getClass()) should it not? But yes, calling getClass() on a null reference will result in NPE.
This answer misses the point -- a null dereference is not relevant because the failure happens outside of the operation (you always need to check for null before you use a reference like that). In general getClass() should not be used with isAssignableFrom in the first place -- the operation is meant for the situation of having no objects. If you have the object reference a, use a instanceof SomeClass (if you do know the type SomeClass) or someObject.getClass().isInstance(a) (if you don't know the type of someObject).
13

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.

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.

2 Comments

actually no answer is really correct isAssignableFrom work w/ classes, Class.isInstance is the analog of 'instanceof'
To put @bestsss's correct comment into concrete code: Because you have an object (this), clazz.isInstance(this) would be better in your example.
7

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

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.

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.

Comments

7

instanceof cannot be used with primitive types or generic types either. 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.

Does not compile due to type erasure removing the runtime reference. However, the code below will compile:

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

Comments

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.class.isAssignableFrom(obj.getClass()) ...

OR

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

4 Comments

That is not true. Please see "Adam Rosenfield" comment stackoverflow.com/questions/496928/…
Could you elaborate "That is not true"? The comment you refer to has nothing to do with the scenario in my post. I do have some test code that backs up my explanation.
If you have a non-null reference to an object instance (obj in this example) of any type then you can call the public getClass() method on it to obtain the reflection metadata for the implementing class. This is true even if that implementing class type would not be legally visible at that location at compile time. It's OK at runtime because, for you to hold the obj reference, some code path that ultimately did have legal access to the class created one and gave (leaked?) it to you.
This answer wants to list an analog for obj instanceof A. That would be A.class.isInstance(obj). You should only be using isAssignableFrom if you have two classes and zero objects.
2

It all depends on what you have available at that point in the code. I would not recommend to use isAssignableFrom if you are working with an actual object — there is a better option. Here is a ranked list of recommendations, based on what you have available:

  • If you have an object a and you know the type B at compile time:

    a instanceof B

  • If you have an object a and you don't know the type B, but you have an object b:

    b.getClass().isInstance(a)

  • If you have an object a and you don't have a type at compile time OR an instantiated object, but you do have a class object Class<?> someBClass:

    someBClass.isInstance(a)

  • If you have no instantiated objects, but you have two Class<?> objects:

    someBClass.isAssignableFrom(someAClass).

Assuming you start at the top of the list and work down, each one of these is the simplest way to accomplish your goal, and based on my own research I believe that you will also get the best possible performance.

Comments

1

How about some examples to show it in action...

@Test public void isInstanceOf() { Exception anEx1 = new Exception("ex"); Exception anEx2 = new RuntimeException("ex"); RuntimeException anEx3 = new RuntimeException("ex"); //Base case, handles inheritance Assert.assertTrue(anEx1 instanceof Exception); Assert.assertTrue(anEx2 instanceof Exception); Assert.assertTrue(anEx3 instanceof Exception); //Other cases Assert.assertFalse(anEx1 instanceof RuntimeException); Assert.assertTrue(anEx2 instanceof RuntimeException); Assert.assertTrue(anEx3 instanceof RuntimeException); } @Test public void isAssignableFrom() { Exception anEx1 = new Exception("ex"); Exception anEx2 = new RuntimeException("ex"); RuntimeException anEx3 = new RuntimeException("ex"); //Correct usage = The base class goes first Assert.assertTrue(Exception.class.isAssignableFrom(anEx1.getClass())); Assert.assertTrue(Exception.class.isAssignableFrom(anEx2.getClass())); Assert.assertTrue(Exception.class.isAssignableFrom(anEx3.getClass())); //Incorrect usage = Method parameter is used in the wrong order Assert.assertTrue(anEx1.getClass().isAssignableFrom(Exception.class)); Assert.assertFalse(anEx2.getClass().isAssignableFrom(Exception.class)); Assert.assertFalse(anEx3.getClass().isAssignableFrom(Exception.class)); } 

Comments

1

Just an addition to the comments above.

When you have the instances of A and B classes the equivalence is true: b instanceOf A <=> a.getClass().isAssignableFrom(B.class), and instanceOf is more convennient.

But as instance of needs some instance of the left side, isAssignableFrom() comes handy when you do not have it, e.g. when you use reflection and need to check whether you can assign a field's value to a variable:

Field field = ...; if (A.class.isAssignableFrom(field.getType())) { A someA = (A)field.get(instanceWithTheField); ... } 

Comments

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

1 Comment

Please explain what this code does and how it answers the question.
0

Talking in terms of performance "2" (with JMH):

class A{} class B extends A{} public class InstanceOfTest { public static final Object a = new A(); public static final Object b = new B(); @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public boolean testInstanceOf() { return b instanceof A; } @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public boolean testIsInstance() { return A.class.isInstance(b); } @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public boolean testIsAssignableFrom() { return A.class.isAssignableFrom(b.getClass()); } public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(InstanceOfTest.class.getSimpleName()) .warmupIterations(5) .measurementIterations(5) .forks(1) .build(); new Runner(opt).run(); } } 

It gives:

Benchmark Mode Cnt Score Error Units InstanceOfTest.testInstanceOf avgt 5 1,972 ? 0,002 ns/op InstanceOfTest.testIsAssignableFrom avgt 5 1,991 ? 0,004 ns/op InstanceOfTest.testIsInstance avgt 5 1,972 ? 0,003 ns/op 

So that we can conclude: instanceof as fast as isInstance() and isAssignableFrom() not far away (+0.9% executon time). So no real difference whatever you choose

Comments

-3

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.

2 Comments

Hm, if you have a bottleneck in instanceof, I believe you have serious design problems...
The answer by JBE presents a hypothesis which differs from your hypothesis.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.