instanceof Operator
The instanceof operator answers one simple question: does this object belong to a given type? It returns true or false and is most often used right before a cast so you never get a surprise ClassCastException at runtime.
Basic Syntax
object instanceof ClassName
If object is an instance of ClassName (or any subclass / implementing class of it), the expression evaluates to true. If object is null, it always evaluates to false — no NullPointerException.
class Animal {}
class Dog extends Animal {}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
System.out.println(a instanceof Dog); // true
System.out.println(a instanceof Animal); // true — Dog IS-A Animal
System.out.println(a instanceof Object); // true — everything IS-A Object
Animal b = null;
System.out.println(b instanceof Dog); // false — null is never an instance
}
}
Output:
true
true
true
false
Note:
instanceofchecks the runtime type of the object, not the declared (compile-time) type of the variable. Even thoughais declared asAnimal, the object it points to was created asDog, soa instanceof Dogistrue.
Why You Need instanceof Before Casting
Inheritance lets you store a Dog in an Animal variable. That’s fine going up the hierarchy (upcasting). Going down (downcasting) is where bugs hide:
Animal a = new Animal(); // NOT a Dog this time
// Without instanceof check — DANGEROUS:
Dog d = (Dog) a; // Compiles fine, crashes at runtime!
// Throws: ClassCastException: Animal cannot be cast to Dog
The safe pattern is to check, then cast:
Animal a = new Animal();
if (a instanceof Dog) {
Dog d = (Dog) a;
d.bark(); // safe — we confirmed the type first
} else {
System.out.println("Not a Dog, skipping bark.");
}
Output:
Not a Dog, skipping bark.
Warning: Skipping the
instanceofcheck before a downcast is one of the most common runtime errors in Java. Always guard casts unless you have ironclad knowledge of the actual type.
Using instanceof with Interfaces
instanceof works just as well against interfaces — it checks whether the object’s class implements the interface.
interface Flyable {
void fly();
}
class Bird implements Flyable {
public void fly() { System.out.println("Bird flying"); }
}
class Cat {}
public class Main {
public static void main(String[] args) {
Object obj1 = new Bird();
Object obj2 = new Cat();
if (obj1 instanceof Flyable f) { // pattern matching (Java 16+)
f.fly();
}
System.out.println(obj2 instanceof Flyable); // false
}
}
Output:
Bird flying
false
Pattern Matching with instanceof (Java 16+)
Java 16 made a quality-of-life improvement: you can declare a pattern variable right inside the instanceof test. If the test passes, the variable is automatically cast and in scope — no separate cast line needed.
class Shape {}
class Circle extends Shape {
double radius;
Circle(double r) { this.radius = r; }
}
class Rectangle extends Shape {
double width, height;
Rectangle(double w, double h) { this.width = w; this.height = h; }
}
public class Main {
static double area(Shape s) {
if (s instanceof Circle c) {
return Math.PI * c.radius * c.radius;
} else if (s instanceof Rectangle r) {
return r.width * r.height;
}
return 0;
}
public static void main(String[] args) {
System.out.printf("Circle area: %.2f%n", area(new Circle(5)));
System.out.printf("Rectangle area: %.2f%n", area(new Rectangle(4, 6)));
}
}
Output:
Circle area: 78.54
Rectangle area: 24.00
The pattern variable (c, r) is only in scope inside the if block where the check succeeded, so the compiler guarantees it is safe to use without an extra cast.
Tip: Pattern matching
instanceofis finalized in Java 16. If you’re on Java 8–15, you still need the classic two-step: check then cast.
instanceof and Inheritance Hierarchy
Understanding which checks return true is crucial when you have a deeper hierarchy:
class Vehicle {}
class Car extends Vehicle {}
class ElectricCar extends Car {}
public class Main {
public static void main(String[] args) {
ElectricCar ec = new ElectricCar();
System.out.println(ec instanceof ElectricCar); // true
System.out.println(ec instanceof Car); // true
System.out.println(ec instanceof Vehicle); // true
System.out.println(ec instanceof Object); // true
Car c = new Car();
System.out.println(c instanceof ElectricCar); // false — Car is NOT an ElectricCar
}
}
Output:
true
true
true
true
false
Think of it as asking: “Is this object at least of this type?” It succeeds for the object’s own class and every ancestor class or interface up the chain.
Comparison: Classic vs Pattern Matching
| Feature | Classic (pre-16) | Pattern Matching (16+) |
|---|---|---|
| Syntax | obj instanceof Foo | obj instanceof Foo f |
| Requires separate cast? | Yes | No |
| Variable scope | N/A | Inside the if block |
| Null safe? | Yes | Yes |
| Java version | All versions | Java 16+ (finalized) |
Common Pitfall: Comparing Unrelated Types
The compiler catches one category of mistake for you: if the two types are completely unrelated and no subtyping relationship is possible, it reports a compile error.
String s = "hello";
// System.out.println(s instanceof Integer); // Compile error — String can never be Integer
However, with interfaces or generic types the compiler is more lenient. Keep this in mind when writing defensive checks.
Under the Hood
At the bytecode level, instanceof compiles to the instanceof JVM instruction (0xC1). The JVM walks the object’s class hierarchy stored in the class metadata area of the heap to determine whether the target type appears anywhere in the chain.
For pattern matching variables, the compiler generates the cast instruction automatically right after the instanceof check, so there is no extra overhead compared to the classic check-then-cast pattern — it is purely syntactic sugar.
Performance-wise, instanceof is very fast. The JIT compiler (see JIT Compilation) can often inline and optimize type checks, especially in tight loops or polymorphic call sites tracked by the JVM’s profiling data.
One subtlety: because instanceof relies on the runtime class loader chain, two classes with the same fully-qualified name loaded by different class loaders are considered distinct types. This matters in OSGi containers, plugin frameworks, and application servers — obj instanceof Foo can return false even if the class looks identical, because they are different Class objects. See Class Loaders for details.
Quick Reference
// 1. Simple check
System.out.println("hi" instanceof String); // true
// 2. Null safety
Object o = null;
System.out.println(o instanceof String); // false (no NPE)
// 3. Classic guard-and-cast
if (animal instanceof Dog) {
Dog d = (Dog) animal;
d.bark();
}
// 4. Pattern matching (Java 16+)
if (animal instanceof Dog d) {
d.bark(); // d already cast, no boilerplate
}
Related Topics
- Runtime Polymorphism — how the JVM dispatches method calls at runtime, closely related to
instanceofchecks - Inheritance — understanding the type hierarchy that
instanceoftraverses - Pattern Matching — Java 21’s extended pattern matching in
switchexpressions builds directly oninstanceofpatterns - Casting & Types — a look at Java’s primitive and reference type system
- vtable & Dynamic Dispatch — the low-level mechanism behind how the JVM resolves object types at runtime
- Abstract Class vs Interface — knowing when to use abstract classes vs interfaces helps you write cleaner
instanceofchecks