Java provides three main ways to check type compatibility. Functionally, they are similar but are used in different contexts. Here they are, ordered by
performance:
instanceof. This binary operator is the fastest and most commonly used. If you have an instance of
A and can specify
B explicitly, this is the preferred choice. If
A (or more precisely, the type of the variable holding an instance of
A) and
B are not in the same inheritance chain, the instance cannot possibly be a subtype of
B, and the compilation will fail with an
inconvertible types error.
Class::isInstance. This method takes an object of type A as a parameter. It should be chosen when you have an instance of
A available, but
B is not known at compile time. For instance, if you have variables
A a and
Class bClass, you can check with
bClass.isInstance(a).
Class::isAssignableFrom. This method takes
Class<A>. It’s the only option left if you don't have an instance of
A. You would use it as
bClass.isAssignableFrom(aClass).
There is also a fourth method – attempting to cast an instance of type
A to type
B. If the types are incompatible, this cast will throw a
ClassCastException. However, this is universally considered a poor practice, as building program logic on the basis of exceptions is not advisable. The reasoning behind this is detailed in
Effective Java Item 57.