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.
Great article, helped me understand which way to use.
ReplyDeleteFound a cock-up:
ReplyDeleteAll 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
Thanks, I have updated the post. isInstance() cannot be used to directly check whether a class implements an interface.
Delete