🧬 Inheritance & Polymorphism · Intermediate

instanceof & pattern matching in Java

if (o instanceof String s) binds a typed variable.

🧩 The mysteryCheck the type, then cast, then use — three steps, and the cast could be to the wrong type. Java 16 squashed them into one safe move.

instanceof asks "are you a...?"

x instanceof Dog is true if x is a Dog or a subtype of Dog. For null it's always false — it never throws.

Object o = "Java";
boolean a = o instanceof String;  // true
boolean b = o instanceof Integer; // false

Test, cast, use

✗ Old style
if (o instanceof String) {
    String s = (String) o;
    use(s.length());
}

Repeats the type; easy to cast to the wrong one.

✓ Pattern matching
if (o instanceof String s) {
    use(s.length());
}

Tests and binds s, already cast (Java 16).

🔮 Predict it

Test and use in one breath

What does this print?

Object o = 7;
if (o instanceof Integer n && n > 5) {
    System.out.println("big " + (n * 2));
} else {
    System.out.println("small");
}
  1. big 14
  2. big 72
  3. small
Show the answer

big 14. o is an Integer, so n is bound. && only evaluates n > 5 when the match succeeded, so n is safe to use there.

🔮 Predict it

Is null an Object?

What does this print?

Object o = null;
System.out.println(o instanceof Object);
  1. true
  2. false
  3. Throws NullPointerException
Show the answer

false — even for Object. instanceof checks the object, and null refers to no object at all.

⚠️ The trap

|| breaks the binding

With ||, the right side runs only when the left side was false — when the match failed. So s isn't bound there, and the compiler refuses: it cannot find s. && works; || doesn't.

if (o instanceof String s || s.isEmpty()) {
    // compile error: s not in scope
}

Flow scoping

The compiler tracks where a match is certain. If a failed match makes the method return, then s is bound for everything after the if. This early-exit style avoids deep nesting.

if (!(o instanceof String s)) {
    return;
}
System.out.println(s.length()); // OK
💼 In the real world

In real projects

You'll write o instanceof Point p && x == p.x in nearly every equals method. And pattern matching grew from here: switch patterns and record patterns (Java 21) build on exactly this idea.

Key takeaways

  1. instanceof is false for null
  2. o instanceof String s tests and casts in one go
  3. s is in scope only where the match is certain
  4. Works with && but not with ||
🤯 Did you know?

Pattern matching for instanceof previewed in Java 14 and 15 and became final in Java 16 (JEP 394).

Practice questions

What does this print?

Object o = 42;
if (o instanceof Integer i && i > 40) {
    System.out.println("big " + (i + 1));
} else {
    System.out.println("other");
}
  1. big 43
  2. big 421
  3. other
  4. Compile error
Check your answer

big 43. o is an Integer, so i is bound. && only evaluates i > 40 when the match succeeded, so i can be used there.

What does this print?

String s = null;
System.out.println(s instanceof String);
  1. true
  2. false
  3. Throws NullPointerException
Check your answer

false. instanceof returns false for null, regardless of the declared type. It never throws.

Next: methods are polymorphic... but fields and static methods are not. Prepare for weirdness.