Sunday, 29 July 2012

Java: instanceof, isAssignableFrom() or isInstance()?

The instanceof, Class.isInstance()and Class.isAssignableFrom() statements all aim at testing whether an object can be casted without triggering an exception.
public class Test { public static class A {}; public static class B extends A {}; public interface I {}; public static void main(String[] args) { A a = new A(); B b = new B(); // // instanceof // if ( B instanceof A ) {} // Illegal if ( B instanceof a ) {} // Illegal if ( b instanceof a ) {} // Illegal if ( b instanceof A ) {} // OK if ( b instanceof I ) {} // OK if ( null instanceof A ) {} // OK if ( b instanceof null ) {} // Illegal if ( b instanceof b.getClass() ) {} // Illegal if ( b instanceof double ) {} // Illegal if ( b instanceof Double ) {} // Illegal if ( b instanceof double.class ) {} // Illegal if ( b instanceof Double.class ) {} // Illegal // // isAssignableFrom() // // All OK if ( A.class.isAssignableFrom(B.class) ) {} if ( A.class.isAssignableFrom(b.getClass()) ) {} if ( a.getClass().isAssignableFrom(B.class) ) {} if ( a.getClass().isAssignableFrom(b.getClass()) ) {} // All OK if ( double.class.isAssignableFrom(double.class) ) {} if ( Double.class.isAssignableFrom(Double.class) ) {} if ( double.class.isAssignableFrom(B.class) ) {} if ( Double.class.isAssignableFrom(b.getClass()) ) {} // All OK if ( I.class.isAssignableFrom(double.class) ) {} if ( I.class.isAssignableFrom(Double.class) ) {} Class c = null; // Throws NullPointerException at runtime if ( A.class.isAssignableFrom(c) ) {} // // isInstance() // b = null; // All OK if ( A.class.isInstance(b) ) {} if ( a.getClass().isInstance(b) ) {} if ( double.class.isInstance(b) ) {} if ( Double.class.isInstance(b) ) {} if ( I.class.isInstance(b) ) {} // Throws NullPointerException at runtime if ( c.isInstance(a) ) {} } } 
About instanceof:
  • The left argument must be a reference to an object
  • The right argument must be a class known at compile time
  • The left argument cannot be a primitive
About isAssignableFrom():
  • The left argument must be a class (not necessarily known at compile time)
  • The right argument must be a class (not necessarily known at compile time)
  • The left argument can be a primitive
About isInstance():
  • The left argument must be a class (not necessarily known at compile time)
  • The right argument must be a reference to an object (eventually null
  • The left argument cannot be null

Conclusion

  • The isAssignableFrom() and isInstance() methods are more flexible than instanceof in that they do not require to know the right argument at compile time.
  • The left argument of instanceof can be null, contrary to the isAssignableFrom() and isInstance() methods.
  • The instanceof statement cannot be used with primitives.
  • Only isInstance() can take a null right parameter without a generating compile time issue or throwing a NullPointerException at runtime.
  • Only instanceof and isAssignableFrom() can be used to directly test interface implementation.
Therefore, the most stress-free solution to check whether an object (null or not) can be cast without triggering an exception at runtime is isInstance(). However, it cannot be used to check whether a Class implements an interface. In this case, isAssignableFrom() remains the best solution.

3 comments:

  1. Great article, helped me understand which way to use.

    ReplyDelete
  2. Found a cock-up:

    All three statements can be used to test interface implementation.

    contradicts

    Therefore, the most stress-free solution to check whether an object (null or not) can be cast without triggering an exception at runtime is isInstance().
    However, it cannot be used to check whether a Class implements an interface. In this case, isAssignableFrom() remains the best solution.

    Nice and clear article nevertheless

    ReplyDelete
    Replies
    1. Thanks, I have updated the post. isInstance() cannot be used to directly check whether a class implements an interface.

      Delete