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

Viewed 276600

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?

15 Answers

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.

There is also another difference:

null instanceof X is false no matter what X is

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

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.

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.

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));
}

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.

Related