1. Introduction
In this quick tutorial, we're going to take a look at the difference between Class.isInstance and Class.isAssignableFrom. We'll learn how to use each method and what the differences are between them.
2. Setup
Let's set up an interface and a couple of classes to use while we explore the Class.isInstance and Class.isAssignableFrom functionality.
First, let's define an interface:
public interface Shape {
}
Next, let's define a class that implements Shape:
public class Triangle implements Shape {
}
Now, we'll create a class that extends Triangle:
public class IsoscelesTriangle extends Triangle {
}
3. Class.isInstance
The isInstance method on the Class class is equivalent to the instanceof operator. The isInstance method was introduced in Java 1.1 because it can be used dynamically. This method will return true if the argument isn't null and can be successfully cast to the reference type without raising a ClassCastException.
Let's look at how we can use the isInstance method with the interface and classes we defined:
@Test
public void whenUsingIsInstanceProperly_desiredResultsHappen() {
Shape shape = new Triangle();
Triangle triangle = new Triangle();
IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle();
Triangle isoscelesTriangle2 = new IsoscelesTriangle();
Shape nonspecificShape = null;
assertTrue(Shape.class.isInstance(shape));
assertTrue(Shape.class.isInstance(triangle));
assertTrue(Shape.class.isInstance(isoscelesTriangle));
assertTrue(Shape.class.isInstance(isoscelesTriangle2));
assertFalse(Shape.class.isInstance(nonspecificShape));
assertTrue(Triangle.class.isInstance(shape));
assertTrue(Triangle.class.isInstance(triangle));
assertTrue(Triangle.class.isInstance(isoscelesTriangle));
assertTrue(Triangle.class.isInstance(isoscelesTriangle2));
assertFalse(IsoscelesTriangle.class.isInstance(shape));
assertFalse(IsoscelesTriangle.class.isInstance(triangle));
assertTrue(IsoscelesTriangle.class.isInstance(isoscelesTriangle));
assertTrue(IsoscelesTriangle.class.isInstance(isoscelesTriangle2));
}
As we can see, the right-hand side can be equivalent to or more specific than the left-hand side. Providing null to the isInstance method returns false.
4. Class.isAssignableFrom
The Class.isAssignableFrom method will return true if the Class on the left-hand side of the statement is the same as or is a superclass or superinterface of the provided Class parameter.
Let's use our classes with the isAssignableFrom method:
@Test
public void whenUsingIsAssignableFromProperly_desiredResultsHappen() {
Shape shape = new Triangle();
Triangle triangle = new Triangle();
IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle();
Triangle isoscelesTriangle2 = new IsoscelesTriangle();
assertFalse(shape.getClass().isAssignableFrom(Shape.class));
assertTrue(shape.getClass().isAssignableFrom(shape.getClass()));
assertTrue(shape.getClass().isAssignableFrom(triangle.getClass()));
assertTrue(shape.getClass().isAssignableFrom(isoscelesTriangle.getClass()));
assertTrue(shape.getClass().isAssignableFrom(isoscelesTriangle2.getClass()));
assertFalse(triangle.getClass().isAssignableFrom(Shape.class));
assertTrue(triangle.getClass().isAssignableFrom(shape.getClass()));
assertTrue(triangle.getClass().isAssignableFrom(triangle.getClass()));
assertTrue(triangle.getClass().isAssignableFrom(isoscelesTriangle.getClass()));
assertTrue(triangle.getClass().isAssignableFrom(isoscelesTriangle2.getClass()));
assertFalse(isoscelesTriangle.getClass().isAssignableFrom(Shape.class));
assertFalse(isoscelesTriangle.getClass().isAssignableFrom(shape.getClass()));
assertFalse(isoscelesTriangle.getClass().isAssignableFrom(triangle.getClass()));
assertTrue(isoscelesTriangle.getClass().isAssignableFrom(isoscelesTriangle.getClass()));
assertTrue(isoscelesTriangle.getClass().isAssignableFrom(isoscelesTriangle2.getClass()));
assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(Shape.class));
assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(shape.getClass()));
assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(triangle.getClass()));
assertTrue(isoscelesTriangle2.getClass().isAssignableFrom(isoscelesTriangle.getClass()));
assertTrue(isoscelesTriangle2.getClass().isAssignableFrom(isoscelesTriangle2.getClass()));
}
As with the isInstance example, we can clearly see that the right-hand side must be either the same or more specific than the left-hand side. We can also see that we're never able to assign our Shape interface.
5. The Differences
Now that we've laid out a couple of detailed examples, let's go over some of the differences:
- In order to use isInstance, we need to know what one of the classes is at compile time.
- Only isAssignableFrom can be used with primitives. We should note that if we're using primitives, the method will only return true if the Class object and Class parameter are exactly the same Class.
- The isAssignableFrom method will throw a NullPointerException if the object used on either side of the expression is null. If you provide a null to the isInstance method, it will return false.
- We should think of isInstance as answering the question of whether the provided object is the type we're comparing it to (either directly or via interface or inheritance). We can think of isAssignableFrom as answering the question of whether we can define the parameter class as the object class. In other words, will Triangle triangle = new IsoscelesTriange() compile?
6. Conclusion
In this short tutorial, we looked at both the Class.isInstance and Class.isAssignableFrom methods and explored their use and how they differ.
As always, the example code for this tutorial can be found over on GitHub.