☕ Java OOP Series

instanceof
Complete Deep Dive

Operator kya hai, memory mein kaise kaam karta hai, type checking, polymorphism, pattern matching (Java 16+) — sab kuch ek hi jagah, depth mein.

9
Chapters
35+
Code Examples
20+
Practice Programs
Java 16+
Pattern Matching
Full
Theory Covered
01

instanceof Kya Hai?

Complete Theory · JVM Internal · Type Hierarchy · Why It Exists · Use Cases

📖 Core Definition

instanceof — Ek Binary Operator

instanceof Java ka ek binary operator hai jo check karta hai ki koi object kisi particular class ka instance hai ya nahi — ya kisi interface ko implement karta hai ya nahi. Ye runtime type checking karta hai aur hamesha true ya false return karta hai.

Syntax: objectReference instanceof ClassName — agar object given type ka hai ya uske subtype ka hai, to true return hota hai. Agar reference null hai to hamesha false return hota hai (NullPointerException nahi aata).

Ye operator OOP ke ek fundamental problem ko solve karta hai: "Runtime pe ye kaise pata chalega ki is reference ke andar actually konse type ka object hai?" — kyunki polymorphism ki wajah se compile time pe hamesha pata nahi hota.

Formal Definition: The instanceof operator is a binary relational operator that tests whether an object is an instance of a specified type (class, subclass, or interface implementation). It performs a runtime type check using the JVM's internal type descriptor of the object and returns a boolean result.
instanceof — Class Hierarchy Example
Object
Animal (abstract)
Dog
Cat
Dog d = new Dog() ke liye:
d instanceof Dog → true  |  d instanceof Animal → true  |  d instanceof Object → true  |  d instanceof Cat → false
🧠 JVM Internal — Kaise Kaam Karta Hai?

Runtime Type Information (RTTI)

Jab aap Java mein koi object banate ho, JVM us object ke saath ek type descriptor (internal metadata) store karta hai heap memory mein. Ye descriptor batata hai ki object actually konse class ka hai, uski superclasses kya hain, aur usne konse interfaces implement kiye hain.

instanceof check karte waqt JVM ye karta hai:

  • Step 1: Left side ka reference null hai? → false return karo immediately
  • Step 2: Object ke runtime type descriptor se class hierarchy extract karo
  • Step 3: Check karo ki right side ki class/interface, object ki type chain mein hai ya nahi
  • Step 4: Hai to true, nahi to false

Ye check O(depth of hierarchy) time leta hai — typically very fast (microseconds). JIT compiler aksar ise inline bhi kar deta hai.

⚡ Compile Time Check Bhi Hoti Hai

instanceof — Compile + Runtime Dono

Interesting baat: instanceof sirf runtime check nahi hai — compiler bhi kuch checks karta hai. Agar compiler ko pata hai ki do types ka koi relationship hi nahi ho sakta (e.g., String s; s instanceof Integer), to compile-time error aayega, runtime tak wait nahi karega.

Example: String s = "hello"; if(s instanceof Integer) — ye compile error dega kyunki String aur Integer same hierarchy mein nahi hain aur String final hai.

Lekin agar dono types mein parent-child relationship ho sakti ho (one is an interface, or one could be a subtype), to compile time pe allow kiya jaata hai, runtime pe check hota hai.

🔍

Runtime Check

Actual type ki jaanch runtime pe hoti hai — JVM ke type descriptor se.

🌳

Hierarchy Aware

Puri class chain check karta hai — superclass, interface, sab include hain.

🛡️

Null Safe

null instanceof X hamesha false — koi NullPointerException nahi aati.

Boolean Result

Hamesha true ya false return karta hai — koi exception nahi.

🔗

Interface Check

Classes ke alawa interfaces bhi check kar sakta hai — obj instanceof Comparable.

🆕

Pattern Matching

Java 16+ mein instanceof + variable declare ek line mein — if (x instanceof Dog d).

🌐 Real-World Backend Use Cases

instanceof Kahaan Use Hota Hai?

  • Exception Handling: Catch block mein multiple exception types handle karna — if (e instanceof IOException)
  • Visitor Pattern: AST (Abstract Syntax Tree) nodes process karna — compilers, query parsers
  • Serialization: Object ka actual type detect karna aur accordingly serialize karna
  • Event Systems: Incoming event ko actual type ke hisaab se route karna
  • Plugin Systems: Runtime pe plugin capabilities check karna
  • equals() Method: Two objects compare karne se pehle same type check karna — standard Java practice
  • REST API Handlers: Request body ka type check karke appropriate handler call karna
  • Collections Processing: Mixed-type collections mein specific types filter karna
02

Basic Syntax

Syntax Rules · Downcasting · ClassCastException Prevention · Truth Table

📖 Complete Syntax

instanceof — Poora Syntax Guide

Basic form: variable instanceof TypeName — left side reference variable, right side class/interface name (not a variable, hardcoded type).

Pattern matching (Java 16+): variable instanceof TypeName localVar — check ke saath directly new variable declare karo, casting ki zaroorat nahi.

Negation: !(obj instanceof TypeName) ya Java 16+ mein !(obj instanceof TypeName t) — scope ke andar variable accessible hota hai.

Safe Casting Pattern: Hamesha pehle instanceof se check karo, phir cast karo. Bina check ke cast karna → ClassCastException risk.

Safe Casting Flow — instanceof + Cast
STEP 1Reference hai
Object obj
STEP 2instanceof check
if obj instanceof Dog
STEP 3Safe Cast
Dog d = (Dog)obj
USESafe Access
d.bark()
instanceof Truth Table — class Animal, Dog extends Animal, Cat extends Animal
Expression Object Created Result Reason
dog instanceof Dognew Dog()trueSame class
dog instanceof Animalnew Dog()trueDog is-a Animal (superclass)
dog instanceof Objectnew Dog()trueAll objects extend Object
dog instanceof Catnew Dog()falseNo Dog-Cat relationship
animal instanceof Dognew Animal()falseAnimal is NOT Dog (parent ≠ child)
animal instanceof Dognew Dog()trueRuntime type is Dog, not Animal
null instanceof Dognullfalsenull is never an instance of anything
null instanceof Objectnullfalsenull ka koi runtime type nahi
EX 2.1

Basic instanceof — Sab Cases Ek Saath

Simple class hierarchy se sab true/false cases verify karo — runtime type vs declared type ka concept samjho.
public class BasicInstanceof {

    // Simple class hierarchy
    static class Animal {
        void eat() { System.out.println("Animal eats"); }
    }
    static class Dog extends Animal {
        void bark() { System.out.println("Dog barks!"); }
    }
    static class Cat extends Animal {
        void meow() { System.out.println("Cat meows!"); }
    }
    static class GoldenRetriever extends Dog {
        void fetch() { System.out.println("Fetching!"); }
    }

    public static void main(String[] args) {

        Dog    dog    = new Dog();
        Cat    cat    = new Cat();
        Animal animal = new Animal();
        GoldenRetriever gr = new GoldenRetriever();

        System.out.println("── Dog object checks ──");
        System.out.println("dog instanceof Dog:    "    + (dog instanceof Dog));     // true
        System.out.println("dog instanceof Animal: "    + (dog instanceof Animal));  // true  — subtype
        System.out.println("dog instanceof Object: "    + (dog instanceof Object));  // true  — all objects
        System.out.println("dog instanceof Cat:    "    + (dog instanceof Cat));     // false — sibling

        System.out.println("\n── GoldenRetriever (3 levels deep) ──");
        System.out.println("gr instanceof GoldenRetriever: " + (gr instanceof GoldenRetriever)); // true
        System.out.println("gr instanceof Dog:             " + (gr instanceof Dog));             // true
        System.out.println("gr instanceof Animal:          " + (gr instanceof Animal));          // true
        System.out.println("gr instanceof Object:          " + (gr instanceof Object));          // true
        System.out.println("gr instanceof Cat:             " + (gr instanceof Cat));             // false

        System.out.println("\n── Parent object check ──");
        System.out.println("animal instanceof Animal: " + (animal instanceof Animal));  // true
        System.out.println("animal instanceof Dog:    " + (animal instanceof Dog));     // false! parent ≠ child

        System.out.println("\n── Null check ──");
        Animal nullRef = null;
        System.out.println("null instanceof Animal: "  + (nullRef instanceof Animal));  // false — no NPE!
        System.out.println("null instanceof Object: "  + (nullRef instanceof Object));  // false
    }
}
▶ Output
── Dog object checks ── dog instanceof Dog: true dog instanceof Animal: true dog instanceof Object: true dog instanceof Cat: false ── GoldenRetriever (3 levels deep) ── gr instanceof GoldenRetriever: true gr instanceof Dog: true gr instanceof Animal: true gr instanceof Object: true gr instanceof Cat: false ── Parent object check ── animal instanceof Animal: true animal instanceof Dog: false ── Null check ── null instanceof Animal: false null instanceof Object: false
EX 2.2

instanceof + Downcast — Safe Pattern

Polymorphic reference ko specific type mein cast karna — hamesha instanceof pehle check karo, warna ClassCastException.
public class SafeCasting {

    static class Shape {
        void draw() { System.out.println("Drawing shape"); }
    }
    static class Circle extends Shape {
        double radius;
        Circle(double r) { radius = r; }
        double area() { return Math.PI * radius * radius; }
    }
    static class Rectangle extends Shape {
        double w, h;
        Rectangle(double w, double h) { this.w = w; this.h = h; }
        double area() { return w * h; }
    }

    // Mixed shapes ko process karo
    static void processShape(Shape s) {
        System.out.println("Processing: " + s.getClass().getSimpleName());

        // ✅ SAFE: pehle instanceof check, phir cast
        if (s instanceof Circle) {
            Circle c = (Circle) s;           // safe downcast
            System.out.printf("  Circle area = %.2f%n", c.area());
        } else if (s instanceof Rectangle) {
            Rectangle r = (Rectangle) s;    // safe downcast
            System.out.printf("  Rectangle area = %.2f%n", r.area());
        } else {
            System.out.println("  Unknown shape — draw only");
        }
    }

    public static void main(String[] args) {
        Shape[] shapes = {
            new Circle(5.0),
            new Rectangle(4.0, 6.0),
            new Circle(3.0),
            new Shape()
        };
        for (Shape s : shapes) processShape(s);

        System.out.println("\n── ClassCastException Prevention ──");
        Shape genericShape = new Shape();

        // ❌ UNSAFE: bina check ke cast — ClassCastException!
        try {
            Circle bad = (Circle) genericShape;  // boom!
        } catch (ClassCastException e) {
            System.out.println("ClassCastException: " + e.getMessage());
        }

        // ✅ SAFE: instanceof check se bachao
        if (genericShape instanceof Circle) {
            Circle safe = (Circle) genericShape;
        } else {
            System.out.println("Not a Circle — skip kiya safely.");
        }
    }
}
▶ Output
Processing: Circle Circle area = 78.54 Processing: Rectangle Rectangle area = 24.00 Processing: Circle Circle area = 28.27 Processing: Shape Unknown shape — draw only ── ClassCastException Prevention ── ClassCastException: class Shape cannot be cast to class Circle Not a Circle — skip kiya safely.
EX 2.3

Polymorphic Reference ka Magic

Compile-time declared type vs runtime actual type — ye confusion instanceof ke bina bahut bada problem hai.
public class PolymorphicRef {

    static class Vehicle { String type = "Vehicle"; }
    static class Car extends Vehicle {
        String type = "Car";
        void drive() { System.out.println("Car driving!"); }
    }
    static class ElectricCar extends Car {
        String type = "ElectricCar";
        void charge() { System.out.println("Charging battery..."); }
    }

    public static void main(String[] args) {
        // Runtime type: ElectricCar, Declared type: Vehicle
        Vehicle v = new ElectricCar();

        System.out.println("Declared type:  Vehicle");
        System.out.println("Runtime class:  " + v.getClass().getSimpleName());

        // Compile-time: v sirf Vehicle methods dekh sakta hai
        // Runtime: actual object ElectricCar hai
        System.out.println("\ninstanceof checks on Vehicle ref (actual: ElectricCar):");
        System.out.println("v instanceof Vehicle:     "     + (v instanceof Vehicle));     // true
        System.out.println("v instanceof Car:         "     + (v instanceof Car));         // true!
        System.out.println("v instanceof ElectricCar: "     + (v instanceof ElectricCar)); // true!

        // Without instanceof — compile error (v.drive() not accessible)
        // v.drive();  ← COMPILE ERROR: Vehicle has no drive() method

        // With instanceof — safe, full access
        if (v instanceof ElectricCar) {
            ElectricCar ec = (ElectricCar) v;
            ec.drive();    // inherited from Car
            ec.charge();   // ElectricCar specific
        }

        // Array of mixed vehicles
        Vehicle[] fleet = {
            new Vehicle(),
            new Car(),
            new ElectricCar(),
            new Car()
        };

        System.out.println("\nFleet analysis:");
        int regularCars = 0, electricCars = 0;
        for (Vehicle veh : fleet) {
            if      (veh instanceof ElectricCar) electricCars++;
            else if (veh instanceof Car)         regularCars++;
        }
        System.out.println("Regular Cars: "  + regularCars);
        System.out.println("Electric Cars: " + electricCars);
    }
}
▶ Output
Declared type: Vehicle Runtime class: ElectricCar instanceof checks on Vehicle ref (actual: ElectricCar): v instanceof Vehicle: true v instanceof Car: true! v instanceof ElectricCar: true! Car driving! Charging battery... Fleet analysis: Regular Cars: 2 Electric Cars: 1
03

Inheritance & instanceof

Multi-level Hierarchy · Abstract Classes · equals() Method · Object Class

📖 Theory

Inheritance Chain Mein instanceof

Jab class hierarchy multi-level hoti hai (A extends B extends C extends D), tab instanceof poori chain check karta hai. Koi bhi ancestor (parent, grandparent, great-grandparent) match karega to true return hoga.

Ye "is-a" relationship test karta hai — OOP ka fundamental principle. Dog is-a Animal, is-a Object — isliye ek Dog object teeno ke saath instanceof test pass karta hai.

Important: Reverse nahi hota — Animal is NOT-a Dog. Parent reference se child-specific methods access karne ke liye downcast + instanceof zaroori hai.

EX 3.1

Multi-level Hierarchy — Complete Chain Check

4-level deep hierarchy — har level pe instanceof ka behavior dekho. Abstract class bhi check hoti hai.
public class MultiLevelHierarchy {

    abstract static class LivingBeing {
        abstract void breathe();
    }
    abstract static class Animal extends LivingBeing {
        abstract void move();
    }
    static class Mammal extends Animal {
        void breathe() { System.out.println("Breathing with lungs"); }
        void move()    { System.out.println("Moving on legs"); }
        void warmBlood() { System.out.println("Warm-blooded"); }
    }
    static class Dog extends Mammal {
        void bark() { System.out.println("Woof!"); }
    }
    static class Labrador extends Dog {
        void fetch() { System.out.println("Fetching ball!"); }
    }

    public static void main(String[] args) {
        Labrador lab = new Labrador();

        System.out.println("── Labrador instanceof checks (bottom-up) ──");
        System.out.printf("%-35s %s%n", "lab instanceof Labrador:",    lab instanceof Labrador);    // true
        System.out.printf("%-35s %s%n", "lab instanceof Dog:",         lab instanceof Dog);         // true
        System.out.printf("%-35s %s%n", "lab instanceof Mammal:",      lab instanceof Mammal);      // true
        System.out.printf("%-35s %s%n", "lab instanceof Animal:",      lab instanceof Animal);      // true (abstract!)
        System.out.printf("%-35s %s%n", "lab instanceof LivingBeing:", lab instanceof LivingBeing); // true (abstract!)
        System.out.printf("%-35s %s%n", "lab instanceof Object:",      lab instanceof Object);      // true (always!)

        System.out.println("\n── Process by type ──");
        LivingBeing[] beings = {
            new Labrador(), new Dog(), new Mammal()
        };
        for (LivingBeing b : beings) {
            System.out.print(b.getClass().getSimpleName() + " → ");
            if (b instanceof Labrador) {
                ((Labrador) b).fetch();
            } else if (b instanceof Dog) {
                ((Dog) b).bark();
            } else if (b instanceof Mammal) {
                ((Mammal) b).warmBlood();
            }
        }
    }
}
▶ Output
── Labrador instanceof checks (bottom-up) ── lab instanceof Labrador: true lab instanceof Dog: true lab instanceof Mammal: true lab instanceof Animal: true (abstract!) lab instanceof LivingBeing: true (abstract!) lab instanceof Object: true (always!) ── Process by type ── Labrador → Fetching ball! Dog → Woof! Mammal → Warm-blooded
EX 3.2

equals() Method mein instanceof — Standard Pattern

Java convention: equals() mein instanceof se type check karna mandatory hai — NullPointerException aur ClassCastException dono se bachao.
import java.util.Objects;

public class EqualsPattern {

    static class Student {
        String name;
        int    rollNo;
        double cgpa;

        Student(String name, int rollNo, double cgpa) {
            this.name   = name;
            this.rollNo = rollNo;
            this.cgpa   = cgpa;
        }

        @Override
        public boolean equals(Object obj) {
            // Step 1: Same reference? → definitely equal
            if (this == obj) return true;

            // Step 2: instanceof check — null bhi handle ho jaata hai!
            // null instanceof Student → false, NPE nahi aata
            if (!(obj instanceof Student)) return false;

            // Step 3: Safe cast — already verified hai
            Student other = (Student) obj;

            // Step 4: Field comparison
            return this.rollNo == other.rollNo
                && Objects.equals(this.name, other.name)
                && Double.compare(this.cgpa, other.cgpa) == 0;
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, rollNo, cgpa);
        }

        @Override
        public String toString() {
            return "Student{" + name + ", roll=" + rollNo + ", cgpa=" + cgpa + "}";
        }
    }

    public static void main(String[] args) {
        Student s1 = new Student("Rahul", 101, 8.5);
        Student s2 = new Student("Rahul", 101, 8.5);  // same data
        Student s3 = new Student("Priya", 102, 9.1);  // different

        System.out.println("s1.equals(s2): " + s1.equals(s2));  // true — same data
        System.out.println("s1.equals(s3): " + s1.equals(s3));  // false
        System.out.println("s1.equals(null): " + s1.equals(null)); // false — no NPE!
        System.out.println("s1.equals(\"hello\"): " + s1.equals("hello")); // false — wrong type
        System.out.println("s1 == s2: " + (s1 == s2));       // false — different refs
    }
}
▶ Output
s1.equals(s2): true s1.equals(s3): false s1.equals(null): false ← No NullPointerException! s1.equals("hello"): false ← No ClassCastException! s1 == s2: false
04

Interfaces & instanceof

Interface Checking · Multiple Interfaces · Marker Interfaces · Comparable

📖 Theory — Interface + instanceof

Interface Checking — Class Se Alag Hai

instanceof sirf classes hi nahi, interfaces bhi check kar sakta hai. Ye bahut powerful feature hai — runtime pe ye jaanch sako ki koi object koi capability (interface) provide karta hai ya nahi.

Java mein ek class multiple interfaces implement kar sakti hai. instanceof har ek interface ke liye alag check kar sakta hai. Ye "capability checking" pattern hai — "Kya ye object Comparable hai?" ya "Kya ye Serializable hai?" jaisi checks runtime pe possible hoti hain.

Marker Interfaces: Kuch interfaces ka koi method nahi hota (jaise Serializable, Cloneable) — ye sirf "tag" ke liye hain. instanceof in tagging interfaces ke liye bhi kaam karta hai — JVM ya frameworks runtime pe check karte hain ki koi object "tagged" hai ya nahi.

EX 4.1

Interface instanceof — Capability Checking

Multiple interfaces implement karna — runtime pe capabilities check karo. Real-world plugin/feature detection pattern.
public class InterfaceInstanceof {

    interface Flyable  { void fly();  }
    interface Swimmable{ void swim(); }
    interface Walkable { void walk(); }

    static class Duck implements Flyable, Swimmable, Walkable {
        public void fly()  { System.out.println("Duck flying!");    }
        public void swim() { System.out.println("Duck swimming!");  }
        public void walk() { System.out.println("Duck waddling!");  }
    }
    static class Eagle implements Flyable, Walkable {
        public void fly()  { System.out.println("Eagle soaring!");  }
        public void walk() { System.out.println("Eagle walking!");  }
    }
    static class Fish implements Swimmable {
        public void swim() { System.out.println("Fish swimming!");  }
    }

    static void demonstrateCapabilities(Object obj) {
        System.out.println("\nObject: " + obj.getClass().getSimpleName());
        // Runtime pe capabilities check karo — interface instanceof
        if (obj instanceof Flyable)   ((Flyable)  obj).fly();
        if (obj instanceof Swimmable) ((Swimmable)obj).swim();
        if (obj instanceof Walkable)  ((Walkable) obj).walk();
    }

    public static void main(String[] args) {
        Object[] creatures = { new Duck(), new Eagle(), new Fish() };
        for (Object c : creatures) demonstrateCapabilities(c);

        System.out.println("\n── Interface Type Checks ──");
        Duck duck = new Duck();
        System.out.println("duck instanceof Flyable:   "  + (duck instanceof Flyable));
        System.out.println("duck instanceof Swimmable: "  + (duck instanceof Swimmable));
        System.out.println("duck instanceof Walkable:  "  + (duck instanceof Walkable));

        Eagle eagle = new Eagle();
        System.out.println("eagle instanceof Swimmable:"  + (eagle instanceof Swimmable)); // false!

        // Built-in Java interfaces
        System.out.println("\n── Built-in Interface Checks ──");
        Object[] items = { "Hello", 42, 3.14, new java.util.ArrayList<>() };
        for (Object item : items) {
            System.out.printf("%-12s Comparable:%s  Serializable:%s%n",
                item.getClass().getSimpleName(),
                item instanceof Comparable,
                item instanceof java.io.Serializable);
        }
    }
}
▶ Output
Object: Duck Duck flying! Duck swimming! Duck waddling! Object: Eagle Eagle soaring! Eagle walking! Object: Fish Fish swimming! ── Interface Type Checks ── duck instanceof Flyable: true duck instanceof Swimmable: true duck instanceof Walkable: true eagle instanceof Swimmable:false ── Built-in Interface Checks ── String Comparable:true Serializable:true Integer Comparable:true Serializable:true Double Comparable:true Serializable:true ArrayList Comparable:false Serializable:true
05

Null Behavior

null instanceof · NullPointerException Prevention · Null Safety Patterns

📖 Theory — null aur instanceof

null instanceof — Hamesha false, Koi Exception Nahi

Java specification clearly kehti hai: agar left operand null hai, to instanceof hamesha false return karta hai — bina kisi exception ke. Ye intentional design decision hai.

Iska fayda: agar aap instanceof use kar rahe ho, to alag se null check karne ki zaroorat nahi. Pattern automatically null handle kar leta hai.

Yad rakho: null instanceof Object bhi false hai, kyunki null ka koi runtime type nahi hota — ye sirf "no object" hai.

💡
Golden Rule: Agar aap sirf null check aur cast karne wale ho, to if (obj instanceof SomeType) pehle likhna hi null check hai. Alag se if (obj != null) likhna redundant hai — but explicit null check adds clarity in complex code.
EX 5.1

null + instanceof — Complete Behavior

null ka poora behavior, NPE prevention, aur null-safe patterns — production code mein ye daily use hota hai.
public class NullBehavior {

    static class Box {
        String content;
        Box(String c) { content = c; }
        void open() { System.out.println("Box opened: " + content); }
    }

    static void processBox(Object obj) {
        // Single check handles both: null AND wrong type
        if (obj instanceof Box) {
            Box b = (Box) obj;
            b.open();
        } else {
            System.out.println("Not a Box (or null): " + obj);
        }
    }

    public static void main(String[] args) {
        // null instanceof — NEVER throws NPE
        Object  nullObj    = null;
        String  nullStr    = null;
        Box     nullBox    = null;

        System.out.println("null instanceof Object:  " + (nullObj  instanceof Object));  // false
        System.out.println("null instanceof String:  " + (nullStr  instanceof String));  // false
        System.out.println("null instanceof Box:     " + (nullBox  instanceof Box));     // false

        System.out.println("\n── processBox with different inputs ──");
        processBox(new Box("Surprise!"));  // valid Box
        processBox(null);                  // null — handled gracefully
        processBox("Just a String");       // wrong type — handled
        processBox(42);                     // wrong type — handled

        System.out.println("\n── Without instanceof — NPE danger! ──");
        Object maybeNull = null;

        // ❌ Without check — NPE
        try {
            Box bad = (Box) maybeNull;   // null cast — no exception here...
            bad.open();                 // ...but NPE here!
        } catch (NullPointerException e) {
            System.out.println("NPE caught — bina instanceof ke cast unsafe");
        }

        // ✅ With instanceof — completely safe
        if (maybeNull instanceof Box) {  // null se false milega, no NPE
            ((Box) maybeNull).open();
        } else {
            System.out.println("Safely detected: null ya not-a-Box");
        }

        // Null safety in array processing
        System.out.println("\n── Mixed array with nulls ──");
        Object[] mixed = { new Box("A"), null, "String",
                            new Box("B"), null };
        int count = 0;
        for (Object o : mixed) {
            if (o instanceof Box) count++;  // nulls auto-skipped
        }
        System.out.println("Box count (nulls ignored): " + count);
    }
}
▶ Output
null instanceof Object: false null instanceof String: false null instanceof Box: false ── processBox with different inputs ── Box opened: Surprise! Not a Box (or null): null Not a Box (or null): Just a String Not a Box (or null): 42 ── Without instanceof — NPE danger! ── NPE caught — bina instanceof ke cast unsafe Safely detected: null ya not-a-Box ── Mixed array with nulls ── Box count (nulls ignored): 2
06

Pattern Matching (Java 16+)

instanceof + Variable Declaration · JEP 394 · Switch Pattern (Java 21+) · Cleaner Code

🆕 Java 16+ Feature — JEP 394

Pattern Matching for instanceof

Java 16 (stable) mein ek powerful feature aaya: Pattern Matching for instanceof. Pehle aapko instanceof check karne ke baad manually cast karna padta tha. Ab ek hi statement mein check + cast + variable declaration ho sakti hai.

Old way (Java 15 aur pehle):

  • if (obj instanceof String) { String s = (String) obj; ... } — 2 lines, redundant cast

New way (Java 16+):

  • if (obj instanceof String s) { ... use s directly ... } — 1 line, no cast, cleaner!

Scope rules: Pattern variable s sirf wahan accessible hai jahan guaranteed true hai — if block ke andar. Else block mein ya baad mein nahi. Compiler ye scope enforce karta hai.

🔖
Version Timeline: Java 14 = Preview (JEP 305) → Java 15 = 2nd Preview → Java 16 = Stable (JEP 394). Java 21 mein Switch Pattern Matching bhi stable hua (JEP 441) — switch statement mein bhi case Dog d -> likha ja sakta hai!
EX 6.1

Pattern Matching — Old vs New Comparison

Same problem ko old style aur new pattern matching se solve karo — how much cleaner it gets.
public class PatternMatchingDemo {

    static class Shape  { }
    static class Circle    extends Shape { double radius;    Circle(double r) { radius = r; } }
    static class Rectangle  extends Shape { double w, h;      Rectangle(double w, double h) { this.w=w; this.h=h; } }
    static class Triangle   extends Shape { double base, ht;  Triangle(double b, double h) { base=b; ht=h; } }

    // ── OLD STYLE (before Java 16) ──
    static double areaOld(Shape s) {
        if (s instanceof Circle) {
            Circle c = (Circle) s;           // explicit cast — redundant!
            return Math.PI * c.radius * c.radius;
        } else if (s instanceof Rectangle) {
            Rectangle r = (Rectangle) s;    // explicit cast — redundant!
            return r.w * r.h;
        } else if (s instanceof Triangle) {
            Triangle t = (Triangle) s;      // explicit cast — redundant!
            return 0.5 * t.base * t.ht;
        }
        return 0;
    }

    // ── NEW STYLE (Java 16+) Pattern Matching ──
    static double areaNew(Shape s) {
        if      (s instanceof Circle    c) return Math.PI * c.radius * c.radius;
        else if (s instanceof Rectangle r) return r.w * r.h;
        else if (s instanceof Triangle  t) return 0.5 * t.base * t.ht;
        return 0;
    }

    // ── Java 21+ Switch Pattern ──
    static String describeShape(Shape s) {
        return switch (s) {
            case Circle    c -> "Circle with radius "  + c.radius;
            case Rectangle r -> "Rectangle " + r.w + "×" + r.h;
            case Triangle  t -> "Triangle base=" + t.base;
            default          -> "Unknown shape";
        };
    }

    public static void main(String[] args) {
        Shape[] shapes = {
            new Circle(5),
            new Rectangle(4, 6),
            new Triangle(3, 8)
        };

        System.out.printf("%-25s %-10s %-10s%n", "Shape", "Old Area", "New Area");
        System.out.println("─".repeat(50));
        for (Shape s : shapes) {
            System.out.printf("%-25s %-10.2f %-10.2f%n",
                describeShape(s), areaOld(s), areaNew(s));
        }

        // Pattern matching with condition (Java 21 guarded pattern)
        System.out.println("\n── Pattern with Condition ──");
        Object obj = "Hello World";
        if (obj instanceof String s && s.length() > 5) {
            System.out.println("Long string: " + s.toUpperCase());
        }

        // Scope demonstration
        Object num = 42;
        if (num instanceof Integer i) {
            System.out.println("In if block, i = " + i);  // accessible
        }
        // System.out.println(i);  ← COMPILE ERROR — out of scope
        System.out.println("After if block — i is out of scope");
    }
}
▶ Output
Shape Old Area New Area ────────────────────────────────────────────────── Circle with radius 5.0 78.54 78.54 Rectangle 4.0×6.0 24.00 24.00 Triangle base=3.0 12.00 12.00 ── Pattern with Condition ── Long string: HELLO WORLD In if block, i = 42 After if block — i is out of scope
EX 6.2

Pattern Matching — Real-World JSON-like Processing

Mixed-type values process karna — just like JSON parsing ya event handling mein hota hai. Pattern matching se code kitna clean hota hai dekho.
import java.util.*;

public class JsonLikeProcessor {

    // Simulate JSON values — could be any type
    static String formatValue(Object value) {
        if      (value instanceof String  s)  return "\"" + s + "\"";
        else if (value instanceof Integer i)  return i.toString();
        else if (value instanceof Double  d)  return String.format("%.2f", d);
        else if (value instanceof Boolean b)  return b ? "true" : "false";
        else if (value instanceof List<?> l) return "[array, size=" + l.size() + "]";
        else if (value == null)              return "null";
        else                                  return value.toString();
    }

    static String getType(Object value) {
        if      (value instanceof String)   return "string";
        else if (value instanceof Integer)  return "integer";
        else if (value instanceof Double)   return "float";
        else if (value instanceof Boolean)  return "boolean";
        else if (value instanceof List)     return "array";
        else if (value == null)            return "null";
        else                                return "unknown";
    }

    public static void main(String[] args) {
        // Simulate a JSON response fields
        Map<String, Object> jsonData = new LinkedHashMap<>();
        jsonData.put("name",    "Rahul Kumar");
        jsonData.put("age",     25);
        jsonData.put("cgpa",    8.75);
        jsonData.put("active",  true);
        jsonData.put("courses", List.of("Java", "DSA", "SQL"));
        jsonData.put("nickname",null);

        System.out.println("{\n  Parsed JSON fields:");
        for (Map.Entry<String, Object> entry : jsonData.entrySet()) {
            System.out.printf("  %-12s: %-20s  [type: %s]%n",
                entry.getKey(),
                formatValue(entry.getValue()),
                getType(entry.getValue()));
        }
        System.out.println("}");

        // Compute stats on numeric values only
        System.out.println("\n── Numeric fields sum ──");
        double numericSum = 0;
        for (Object val : jsonData.values()) {
            if      (val instanceof Integer i) numericSum += i;
            else if (val instanceof Double  d) numericSum += d;
        }
        System.out.printf("Sum of numeric values: %.2f%n", numericSum);
    }
}
▶ Output
{ Parsed JSON fields: name : "Rahul Kumar" [type: string] age : 25 [type: integer] cgpa : 8.75 [type: float] active : true [type: boolean] courses : [array, size=3] [type: array] nickname : null [type: null] } ── Numeric fields sum ── Sum of numeric values: 33.75
07

Polymorphism & instanceof

Runtime Polymorphism · Visitor Pattern · Event Systems · Mixed Collections

📖 Theory — Polymorphism Connection

instanceof Polymorphism Ka Companion Hai

Java ka runtime polymorphism (dynamic dispatch) automatically correct method call karta hai. Lekin kuch situations mein aapko specifically jaanna hota hai ki actual runtime type kya hai — yahan instanceof aata hai.

When to use: Jab aap ek polymorphic reference se type-specific actions lena chahte ho jo base class mein nahi hain. Jab mixed-type collections mein se specific types filter karne ho. Jab serialization/deserialization mein type restore karna ho.

Important caveat: Bahut zyada instanceof chains (if-else instanceof chain) usually indicate karte hain ki aapko Visitor Pattern ya abstract methods use karne chahiye — better OOP design. Use it when needed, not as a default.

EX 7.1

Mixed-Type Collection Processing — Real Backend Scenario

E-commerce system: ek hi list mein different payment types — instanceof se route karo. Real Spring Boot service layer mein aisa hota hai.
import java.util.*;

public class PaymentProcessor {

    interface Payment {
        double getAmount();
        String getPaymentId();
    }

    static class CreditCardPayment implements Payment {
        String id, cardNumber, bank;
        double amount;
        CreditCardPayment(String id, String card, String bank, double amt) {
            this.id = id; this.cardNumber = card; this.bank = bank; this.amount = amt;
        }
        public double getAmount() { return amount; }
        public String getPaymentId() { return id; }
    }

    static class UPIPayment implements Payment {
        String id, upiId, app;
        double amount;
        UPIPayment(String id, String upi, String app, double amt) {
            this.id = id; this.upiId = upi; this.app = app; this.amount = amt;
        }
        public double getAmount() { return amount; }
        public String getPaymentId() { return id; }
    }

    static class NetBankingPayment implements Payment {
        String id, bankCode;
        double amount;
        NetBankingPayment(String id, String code, double amt) {
            this.id = id; this.bankCode = code; this.amount = amt;
        }
        public double getAmount() { return amount; }
        public String getPaymentId() { return id; }
    }

    static void processPayment(Payment payment) {
        System.out.printf("\n[%s] Amount: ₹%.2f%n",
            payment.getPaymentId(), payment.getAmount());

        // instanceof — type specific processing
        if (payment instanceof CreditCardPayment cc) {
            System.out.printf("  Type: Credit Card | Bank: %s | Card: ****%s%n",
                cc.bank, cc.cardNumber.substring(cc.cardNumber.length()-4));
            System.out.println("  → Routing to card gateway...");
        } else if (payment instanceof UPIPayment upi) {
            System.out.printf("  Type: UPI | VPA: %s | App: %s%n", upi.upiId, upi.app);
            System.out.println("  → Routing to UPI gateway...");
        } else if (payment instanceof NetBankingPayment nb) {
            System.out.printf("  Type: Net Banking | Bank Code: %s%n", nb.bankCode);
            System.out.println("  → Routing to bank portal...");
        }
    }

    public static void main(String[] args) {
        List<Payment> transactions = List.of(
            new CreditCardPayment("TXN001", "4111111111111234", "HDFC", 2499.00),
            new UPIPayment("TXN002", "rahul@paytm", "Paytm", 599.00),
            new NetBankingPayment("TXN003", "SBI001", 12000.00),
            new UPIPayment("TXN004", "priya@gpay", "Google Pay", 399.00)
        );

        System.out.println("=== PAYMENT GATEWAY PROCESSOR ===");
        transactions.forEach(PaymentProcessor::processPayment);

        // Summary by type
        System.out.println("\n=== SUMMARY ===");
        double cardTotal = 0, upiTotal = 0, nbTotal = 0;
        for (Payment p : transactions) {
            if      (p instanceof CreditCardPayment) cardTotal += p.getAmount();
            else if (p instanceof UPIPayment)         upiTotal  += p.getAmount();
            else if (p instanceof NetBankingPayment)  nbTotal   += p.getAmount();
        }
        System.out.printf("Credit Card: ₹%.2f | UPI: ₹%.2f | Net Banking: ₹%.2f%n",
            cardTotal, upiTotal, nbTotal);
    }
}
▶ Output
=== PAYMENT GATEWAY PROCESSOR === [TXN001] Amount: ₹2499.00 Type: Credit Card | Bank: HDFC | Card: ****1234 → Routing to card gateway... [TXN002] Amount: ₹599.00 Type: UPI | VPA: rahul@paytm | App: Paytm → Routing to UPI gateway... [TXN003] Amount: ₹12000.00 Type: Net Banking | Bank Code: SBI001 → Routing to bank portal... [TXN004] Amount: ₹399.00 Type: UPI | VPA: priya@gpay | App: Google Pay → Routing to UPI gateway... === SUMMARY === Credit Card: ₹2499.00 | UPI: ₹998.00 | Net Banking: ₹12000.00
08

Anti-Patterns & Best Practices

When NOT to Use · Alternatives · getClass() vs instanceof · Performance

⚠️ Anti-Pattern — Excessive instanceof Chains

instanceof Chain — Code Smell

Agar aapke code mein bahut bari if-else instanceof chain hai, ye usually bad OOP design indicate karta hai. Sahi OOP solution: polymorphism — abstract method ya interface method define karo, har subclass mein override karo.

Example: 10 types ke shapes ke liye area calculate karna — ek abstract area() method define karo, har shape mein override karo. instanceof chain ki zaroorat hi nahi.

Acceptable uses: equals() method, external libraries ke types (jo extend nahi kar sakte), deserialization, legacy code integration, capability detection (interface check).

✅ instanceof Kab Use Karo

  • equals() method mein — standard Java pattern
  • External/library types jo extend nahi kar sakte
  • Capability detection (interface check)
  • Null-safe type checking
  • Mixed-type collections filter karna
  • Exception type discrimination

❌ instanceof Mat Karo Jab

  • 5+ types ki if-else chain ho — use polymorphism
  • Har naye subclass pe chain update karni pade
  • Visitor pattern ya abstract method better fit ho
  • Exact type match chahiye (getClass() better)
  • Performance-critical inner loops mein
EX 8.1

getClass() vs instanceof — Important Difference

Ye dono alag hain! instanceof hierarchy-aware hai, getClass() exact match karta hai. equals() mein ye difference critical hai.
public class GetClassVsInstanceof {

    static class Animal { }
    static class Dog extends Animal { }

    public static void main(String[] args) {
        Animal animal = new Dog();  // Runtime: Dog, Declared: Animal

        // instanceof — hierarchy-aware (is-a check)
        System.out.println("instanceof checks:");
        System.out.println("  animal instanceof Dog:    "    + (animal instanceof Dog));    // true
        System.out.println("  animal instanceof Animal: "    + (animal instanceof Animal));  // true

        // getClass() — exact class match (no hierarchy)
        System.out.println("\ngetClass() checks:");
        System.out.println("  getClass() == Dog.class:    "  + (animal.getClass() == Dog.class));    // true
        System.out.println("  getClass() == Animal.class: "  + (animal.getClass() == Animal.class)); // FALSE!

        System.out.println("\nactual class: " + animal.getClass().getSimpleName()); // "Dog"

        // ── When to use which in equals() ──
        System.out.println("\n── equals() design decision ──");
        System.out.println("Use instanceof when:");
        System.out.println("  → Subclass objects should be equal to parent if same data");
        System.out.println("  → Liskov Substitution Principle followed");
        System.out.println("\nUse getClass() when:");
        System.out.println("  → Only exact same type objects should be equal");
        System.out.println("  → Dog.equals(Animal) should be false even with same data");

        // getClass() works on null? NO — NPE!
        Animal nullAnimal = null;
        System.out.println("\nnull instanceof Animal: " + (nullAnimal instanceof Animal)); // false — safe
        try {
            nullAnimal.getClass();  // NPE!
        } catch (NullPointerException e) {
            System.out.println("null.getClass(): NullPointerException!");
        }
    }
}
▶ Output
instanceof checks: animal instanceof Dog: true animal instanceof Animal: true getClass() checks: getClass() == Dog.class: true getClass() == Animal.class: false ← exact match only! actual class: Dog ── equals() design decision ── Use instanceof when: → Subclass objects should be equal to parent if same data → Liskov Substitution Principle followed Use getClass() when: → Only exact same type objects should be equal → Dog.equals(Animal) should be false even with same data null instanceof Animal: false ← safe! null.getClass(): NullPointerException!
EX 8.2

Refactoring — instanceof Chain to Polymorphism

BAD code: long instanceof chain. GOOD code: abstract method. Ye transformation samjho — ye senior developer mindset hai.
public class RefactoringDemo {

    // ❌ BAD: instanceof chain — hard to extend, hard to maintain
    static double areaBAD(Object shape) {
        if (shape instanceof BadCircle) {
            BadCircle c = (BadCircle) shape;
            return Math.PI * c.r * c.r;
        } else if (shape instanceof BadRect) {
            BadRect r = (BadRect) shape;
            return r.w * r.h;
        }
        // Adding new shape? Ye method phir modify karna padega! — Open/Closed Principle violation
        return 0;
    }
    static class BadCircle { double r; BadCircle(double r){ this.r=r; } }
    static class BadRect   { double w,h; BadRect(double w, double h){ this.w=w; this.h=h; } }

    // ✅ GOOD: Polymorphism — adding new shape = just new class, no change here!
    interface GoodShape {
        double area();
        String name();
    }
    static class GoodCircle implements GoodShape {
        double r;
        GoodCircle(double r) { this.r = r; }
        public double area() { return Math.PI * r * r; }
        public String name()  { return "Circle(r=" + r + ")"; }
    }
    static class GoodRect implements GoodShape {
        double w, h;
        GoodRect(double w, double h) { this.w=w; this.h=h; }
        public double area() { return w * h; }
        public String name()  { return "Rect(" + w + "×" + h + ")"; }
    }
    static class GoodTriangle implements GoodShape {
        double b, h;
        GoodTriangle(double b, double h) { this.b=b; this.h=h; }
        public double area() { return 0.5 * b * h; }
        public String name()  { return "Triangle(b=" + b + ")"; }
    }

    public static void main(String[] args) {
        System.out.println("── BAD: instanceof chain ──");
        System.out.printf("Circle area (bad): %.2f%n", areaBAD(new BadCircle(5)));
        System.out.printf("Rect area (bad):   %.2f%n", areaBAD(new BadRect(4, 6)));

        System.out.println("\n── GOOD: Polymorphism — no instanceof needed! ──");
        GoodShape[] shapes = {
            new GoodCircle(5),
            new GoodRect(4, 6),
            new GoodTriangle(3, 8)   // New shape? Zero change to processing code!
        };
        for (GoodShape s : shapes)
            System.out.printf("%-20s area = %.2f%n", s.name(), s.area());
    }
}
▶ Output
── BAD: instanceof chain ── Circle area (bad): 78.54 Rect area (bad): 24.00 ── GOOD: Polymorphism — no instanceof needed! ── Circle(r=5.0) area = 78.54 Rect(4.0×6.0) area = 24.00 Triangle(b=3.0) area = 12.00
09

Practice Programs

Topic-wise 4-5 Problems Each · Click to See Solution

📝

Set A — Basic instanceof (Core Concepts)

Fundamentals solid karo — hierarchy, interfaces, null

1
Type Identifier Method — Object ka Type Identify Karo Ek method likho jo koi bhi Object le aur uska detailed type string return kare: "integer", "floating point", "text", "boolean", "null", "other".
Basicinstanceof Chain
instanceof checks with null check first, then types in order
public class P1_TypeIdentifier {

    static String identify(Object obj) {
        if      (obj == null)             return "null";
        else if (obj instanceof Integer
               || obj instanceof Long
               || obj instanceof Short)  return "integer";
        else if (obj instanceof Double
               || obj instanceof Float)  return "floating point";
        else if (obj instanceof String)    return "text";
        else if (obj instanceof Boolean)   return "boolean";
        else if (obj instanceof int[])     return "int array";
        else                               return "other: " + obj.getClass().getSimpleName();
    }

    public static void main(String[] args) {
        Object[] tests = { 42, 3.14, "hello", true, null,
                           100L, 2.5f, new int[]{1,2,3} };
        for (Object t : tests)
            System.out.printf("%-20s → %s%n",
                String.valueOf(t), identify(t));
    }
}
▶ Output
42 → integer 3.14 → floating point hello → text true → boolean null → null 100 → integer 2.5 → floating point [I@... → int array
2
Vehicle Fleet — Count by Type List of Vehicles hai jisme Car, Truck, Motorcycle mix hain. instanceof se count aur total capacity nikalo.
HierarchyCollection
Vehicle parent, 3 child classes — instanceof se type filter karo
import java.util.*;
public class P2_VehicleFleet {

    static class Vehicle     { String id; Vehicle(String id){ this.id=id; } }
    static class Car         extends Vehicle { int seats; Car(String id, int s){ super(id); seats=s; } }
    static class Truck       extends Vehicle { int loadTons; Truck(String id, int t){ super(id); loadTons=t; } }
    static class Motorcycle  extends Vehicle { boolean sidecar; Motorcycle(String id, boolean s){ super(id); sidecar=s; } }

    public static void main(String[] args) {
        List<Vehicle> fleet = List.of(
            new Car("C01",5), new Truck("T01",10), new Car("C02",7),
            new Motorcycle("M01",false), new Truck("T02",20),
            new Car("C03",4), new Motorcycle("M02",true)
        );

        int cars=0, trucks=0, motos=0;
        int totalSeats=0, totalLoad=0;

        for (Vehicle v : fleet) {
            if      (v instanceof Car c)        { cars++;   totalSeats += c.seats; }
            else if (v instanceof Truck t)      { trucks++; totalLoad  += t.loadTons; }
            else if (v instanceof Motorcycle m) { motos++;  }
        }

        System.out.println("Fleet Summary:");
        System.out.println("  Cars:        " + cars   + " | Total seats: " + totalSeats);
        System.out.println("  Trucks:      " + trucks + " | Total load:  " + totalLoad + " tons");
        System.out.println("  Motorcycles: " + motos);
        System.out.println("  Total fleet: " + fleet.size());
    }
}
▶ Output
Fleet Summary: Cars: 3 | Total seats: 16 Trucks: 2 | Total load: 30 tons Motorcycles: 2 Total fleet: 7
3
implements Serializable Check — Kaunsa Object Serializable Hai? Different objects ki list lo aur check karo kaun Serializable, Comparable, aur Cloneable interface implement karta hai.
Interface CheckBuilt-in Interfaces
java.io.Serializable, java.lang.Comparable, java.lang.Cloneable — all interfaces, instanceof works on all
import java.util.*;
import java.io.Serializable;

public class P3_InterfaceCheck {

    static class NotSerializable { String name = "plain"; }
    static class MySerial implements Serializable {
        private static final long serialVersionUID = 1L;
    }

    public static void main(String[] args) {
        Object[] objects = {
            "hello",         // String
            42,              // Integer
            3.14,            // Double
            new ArrayList<>(), // ArrayList
            new NotSerializable(),
            new MySerial(),
            new HashMap<>()
        };

        System.out.printf("%-18s %-14s %-14s %-14s%n",
            "Class", "Serializable", "Comparable", "Iterable");
        System.out.println("─".repeat(65));

        for (Object o : objects) {
            System.out.printf("%-18s %-14s %-14s %-14s%n",
                o.getClass().getSimpleName(),
                o instanceof Serializable ? "✓ YES" : "✗ NO",
                o instanceof Comparable   ? "✓ YES" : "✗ NO",
                o instanceof Iterable     ? "✓ YES" : "✗ NO");
        }
    }
}
▶ Output
Class Serializable Comparable Iterable ───────────────────────────────────────────────────────────────── String ✓ YES ✓ YES ✗ NO Integer ✓ YES ✓ YES ✗ NO Double ✓ YES ✓ YES ✗ NO ArrayList ✓ YES ✗ NO ✓ YES NotSerializable ✗ NO ✗ NO ✗ NO MySerial ✓ YES ✗ NO ✗ NO HashMap ✓ YES ✗ NO ✗ NO
4
Null-Safe toString() — instanceof + null handle Mixed Object list mein null bhi ho sakti hain. instanceof se safely process karo — NPE avoid karo, descriptive output do.
Null SafetyDefensive Code
instanceof handles null automatically — single check, no separate null guard needed
import java.util.*;
public class P4_NullSafeProcess {

    static String safeDescribe(Object obj) {
        // instanceof handles null — no explicit null check needed!
        if      (obj instanceof String  s) return "String[\"" + s + "\", len=" + s.length() + "]";
        else if (obj instanceof Integer i) return "Integer[" + i + ", even=" + (i%2==0) + "]";
        else if (obj instanceof List<?> l) return "List[size=" + l.size() + "]";
        else if (obj == null)             return "⚠ NULL";
        else                               return "Other[" + obj.getClass().getSimpleName() + "]";
    }

    public static void main(String[] args) {
        Object[] data = {
            "Rahul", null, 42, null, "Java",
            List.of(1,2,3), 99, null, ""
        };

        System.out.println("Processing mixed data (with nulls):");
        int nullCount = 0, strCount = 0, intCount = 0;
        for (int i = 0; i < data.length; i++) {
            System.out.printf("[%d] %s%n", i, safeDescribe(data[i]));
            if      (data[i] == null)           nullCount++;
            else if (data[i] instanceof String)  strCount++;
            else if (data[i] instanceof Integer) intCount++;
        }
        System.out.println("\nSummary: Nulls=" + nullCount +
            ", Strings=" + strCount + ", Integers=" + intCount);
    }
}
▶ Output
[0] String["Rahul", len=5] [1] ⚠ NULL [2] Integer[42, even=true] [3] ⚠ NULL [4] String["Java", len=4] [5] List[size=3] [6] Integer[99, even=false] [7] ⚠ NULL [8] String["", len=0] Summary: Nulls=3, Strings=3, Integers=2
🧩

Set B — OOP + Polymorphism

Real-world class hierarchies, equals(), pattern matching

5
Bank Account System — Transaction Type Routing BankTransaction ke 3 types: Deposit, Withdrawal, Transfer. List mein sab mix hain. instanceof se type-specific processing karo aur summary nikalo.
PolymorphismReal Worldinstanceof Routing
Abstract parent class + 3 child types. instanceof se route karo, Java 16+ pattern matching use karo.
import java.util.*;
public class P5_BankTransactions {

    abstract static class BankTransaction {
        String txnId; double amount;
        BankTransaction(String id, double amt) { txnId=id; amount=amt; }
    }
    static class Deposit    extends BankTransaction {
        String source;
        Deposit(String id, double amt, String src){ super(id,amt); source=src; }
    }
    static class Withdrawal extends BankTransaction {
        String channel;
        Withdrawal(String id, double amt, String ch){ super(id,amt); channel=ch; }
    }
    static class Transfer   extends BankTransaction {
        String toAccount;
        Transfer(String id, double amt, String to){ super(id,amt); toAccount=to; }
    }

    public static void main(String[] args) {
        List<BankTransaction> txns = List.of(
            new Deposit("D001", 5000, "NEFT"),
            new Withdrawal("W001", 1500, "ATM"),
            new Transfer("T001", 3000, "ACC-9876"),
            new Deposit("D002", 8000, "RTGS"),
            new Withdrawal("W002", 2000, "UPI")
        );

        double totalIn=0, totalOut=0, totalTransfer=0;

        for (BankTransaction txn : txns) {
            if (txn instanceof Deposit d) {
                totalIn += d.amount;
                System.out.printf("[%s] DEPOSIT   +₹%.0f via %s%n", d.txnId, d.amount, d.source);
            } else if (txn instanceof Withdrawal w) {
                totalOut += w.amount;
                System.out.printf("[%s] WITHDRAW  -₹%.0f via %s%n", w.txnId, w.amount, w.channel);
            } else if (txn instanceof Transfer t) {
                totalTransfer += t.amount;
                System.out.printf("[%s] TRANSFER  →₹%.0f to %s%n", t.txnId, t.amount, t.toAccount);
            }
        }

        System.out.println("\n── Account Summary ──");
        System.out.printf("Total Deposits:  ₹%.0f%n", totalIn);
        System.out.printf("Total Withdrawn: ₹%.0f%n", totalOut);
        System.out.printf("Total Transfers: ₹%.0f%n", totalTransfer);
        System.out.printf("Net Balance Δ:   ₹%.0f%n", totalIn - totalOut - totalTransfer);
    }
}
▶ Output
[D001] DEPOSIT +₹5000 via NEFT [W001] WITHDRAW -₹1500 via ATM [T001] TRANSFER →₹3000 to ACC-9876 [D002] DEPOSIT +₹8000 via RTGS [W002] WITHDRAW -₹2000 via UPI ── Account Summary ── Total Deposits: ₹13000 Total Withdrawn: ₹3500 Total Transfers: ₹3000 Net Balance Δ: ₹6500
6
Custom equals() — Employee aur Manager Employee class aur Manager (extends Employee) ke liye correct equals() method likho — instanceof use karo. Inheritance ke saath equals() tricky hoti hai.
equals()InheritanceStandard Pattern
Employee equals: instanceof Employee. Manager equals: instanceof Manager + call super.equals + compare extra fields.
import java.util.Objects;
public class P6_EqualsHierarchy {

    static class Employee {
        int    empId;
        String name;
        Employee(int id, String name) { empId=id; this.name=name; }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (!(obj instanceof Employee)) return false;
            Employee e = (Employee) obj;
            return empId == e.empId && Objects.equals(name, e.name);
        }
        public int hashCode() { return Objects.hash(empId, name); }
        public String toString() { return "Employee{"+empId+","+name+"}"; }
    }

    static class Manager extends Employee {
        String department;
        Manager(int id, String name, String dept) { super(id,name); department=dept; }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Manager)) return false;  // Manager-specific check
            Manager m = (Manager) obj;
            return super.equals(m) && Objects.equals(department, m.department);
        }
        public int hashCode() { return Objects.hash(empId, name, department); }
        public String toString() { return "Manager{"+empId+","+name+","+department+"}"; }
    }

    public static void main(String[] args) {
        Employee e1 = new Employee(101, "Rahul");
        Employee e2 = new Employee(101, "Rahul");
        Manager  m1 = new Manager(101, "Rahul", "IT");
        Manager  m2 = new Manager(101, "Rahul", "IT");
        Manager  m3 = new Manager(101, "Rahul", "HR");

        System.out.println("e1.equals(e2):  " + e1.equals(e2));   // true
        System.out.println("m1.equals(m2):  " + m1.equals(m2));   // true — same dept
        System.out.println("m1.equals(m3):  " + m1.equals(m3));   // false — diff dept
        System.out.println("e1.equals(m1):  " + e1.equals(m1));   // true — Employee.equals sees Manager as Employee
        System.out.println("m1.equals(e1):  " + m1.equals(e1));   // false — Manager.equals needs instanceof Manager
        System.out.println("\n[Note: equals() asymmetry is why getClass() is sometimes preferred]");
    }
}
▶ Output
e1.equals(e2): true m1.equals(m2): true m1.equals(m3): false e1.equals(m1): true ← Employee sees Manager as Employee (polymorphism) m1.equals(e1): false ← Manager requires Manager type [Note: equals() asymmetry is why getClass() is sometimes preferred]
7
Notification System — Route by Type Notification ke 4 types: EmailNotif, SMSNotif, PushNotif, InAppNotif. instanceof se appropriate sender call karo. Ye real Spring Boot notification service pattern hai.
Backend Patterninstanceof RoutingReal World
Interface Notification, 4 implementations — router method uses instanceof to dispatch
import java.util.*;
public class P7_NotificationRouter {

    interface Notification { String getRecipient(); String getMessage(); }

    record EmailNotif(String email, String subject, String body) implements Notification {
        public String getRecipient() { return email; }
        public String getMessage()   { return subject; }
    }
    record SMSNotif(String phone, String text) implements Notification {
        public String getRecipient() { return phone; }
        public String getMessage()   { return text; }
    }
    record PushNotif(String deviceId, String title, String body) implements Notification {
        public String getRecipient() { return deviceId; }
        public String getMessage()   { return title; }
    }

    static void send(Notification n) {
        if (n instanceof EmailNotif e) {
            System.out.printf("📧 EMAIL  → %s | Subject: %s | Body: %s%n", e.email(), e.subject(), e.body());
        } else if (n instanceof SMSNotif s) {
            System.out.printf("📱 SMS    → %s | %s%n", s.phone(), s.text());
        } else if (n instanceof PushNotif p) {
            System.out.printf("🔔 PUSH   → %s | %s%n", p.deviceId(), p.title());
        } else {
            System.out.println("❓ Unknown notification type: " + n.getClass().getSimpleName());
        }
    }

    public static void main(String[] args) {
        List<Notification> queue = List.of(
            new EmailNotif("user@example.com", "Order Placed", "Your order #1234 is confirmed"),
            new SMSNotif("+91-9876543210", "OTP: 458921. Valid 5 mins."),
            new PushNotif("DEVICE-ABC-123", "Sale Alert!", "50% off today only"),
            new EmailNotif("admin@shop.com", "Low Stock", "Item X has 2 left"),
            new SMSNotif("+91-8765432109", "Delivery at 3PM today")
        );

        System.out.println("=== Notification Dispatcher ===");
        queue.forEach(P7_NotificationRouter::send);

        System.out.println("\nBreakdown:");
        long emails = queue.stream().filter(n -> n instanceof EmailNotif).count();
        long sms    = queue.stream().filter(n -> n instanceof SMSNotif).count();
        long push   = queue.stream().filter(n -> n instanceof PushNotif).count();
        System.out.printf("Emails: %d, SMS: %d, Push: %d%n", emails, sms, push);
    }
}
▶ Output
=== Notification Dispatcher === 📧 EMAIL → user@example.com | Subject: Order Placed | Body: Your order #1234 is confirmed 📱 SMS → +91-9876543210 | OTP: 458921. Valid 5 mins. 🔔 PUSH → DEVICE-ABC-123 | Sale Alert! 📧 EMAIL → admin@shop.com | Subject: Low Stock | Body: Item X has 2 left 📱 SMS → +91-8765432109 | Delivery at 3PM today Breakdown: Emails: 2, SMS: 2, Push: 1
🎯

Set C — Advanced + Pattern Matching

Exception handling, data pipelines, equals() correctness

8
Exception Type Dispatcher — instanceof in Catch Ek risky operation karo, aur catch mein different exception types ko instanceof se handle karo. SQLException, IOException, NumberFormatException sab alag logic.
Exception HandlingCatch BlockReal Pattern
Catch generic Exception, then instanceof dispatch — useful when single catch handles multiple types
import java.io.*;
import java.sql.SQLException;
public class P8_ExceptionDispatch {

    static void riskyOperation(int scenario) throws Exception {
        switch (scenario) {
            case 1 -> throw new IOException("File not found: data.txt");
            case 2 -> throw new NumberFormatException("Cannot parse 'abc' as int");
            case 3 -> throw new SQLException("Connection refused to DB");
            case 4 -> throw new IllegalArgumentException("Invalid parameter");
            default -> System.out.println("Operation successful!");
        }
    }

    static void handleWithInstanceof(int scenario) {
        try {
            riskyOperation(scenario);
        } catch (Exception e) {
            // instanceof dispatch — single catch, multiple handling strategies
            if (e instanceof IOException io) {
                System.out.println("[IO ERROR] File system issue: " + io.getMessage());
                System.out.println("  → Action: Check file path, retry with backup");
            } else if (e instanceof NumberFormatException nfe) {
                System.out.println("[PARSE ERROR] Data format issue: " + nfe.getMessage());
                System.out.println("  → Action: Validate input before processing");
            } else if (e instanceof SQLException sqle) {
                System.out.println("[DB ERROR] Database issue: " + sqle.getMessage());
                System.out.println("  → Action: Alert DBA, failover to replica");
            } else if (e instanceof IllegalArgumentException iae) {
                System.out.println("[VALIDATION ERROR] " + iae.getMessage());
                System.out.println("  → Action: Return 400 Bad Request to client");
            } else {
                System.out.println("[UNKNOWN] Unexpected: " + e.getClass().getSimpleName());
            }
        }
    }

    public static void main(String[] args) {
        System.out.println("=== Exception Dispatcher ===");
        for (int i = 0; i <= 4; i++) {
            System.out.printf("%nScenario %d: ", i);
            handleWithInstanceof(i);
        }
    }
}
▶ Output
=== Exception Dispatcher === Scenario 0: Operation successful! Scenario 1: [IO ERROR] File system issue: File not found: data.txt → Action: Check file path, retry with backup Scenario 2: [PARSE ERROR] Data format issue: Cannot parse 'abc' as int → Action: Validate input before processing Scenario 3: [DB ERROR] Database issue: Connection refused to DB → Action: Alert DBA, failover to replica Scenario 4: [VALIDATION ERROR] Invalid parameter → Action: Return 400 Bad Request to client
9
Data Pipeline — Filter → Transform → Collect by Type Mixed Object list (Integers, Strings, Doubles, Lists) ko process karo: numeric values sum karo, strings uppercase karo, lists flatten karo. Stream-style chained processing.
Data PipelineStream-likePattern Matching
instanceof filter karo, type-specific transform karo — functional-style pipeline
import java.util.*;
public class P9_DataPipeline {

    public static void main(String[] args) {
        Object[] rawData = {
            42, "hello", 3.14, List.of("a","b"), "world",
            100, null, 2.71, "java", List.of(1,2,3),
            7, "backend", null, 9.99
        };

        double       numericSum = 0;
        List<String> upperStrings = new ArrayList<>();
        List<Object> flattened    = new ArrayList<>();
        int          nullCount = 0;

        for (Object item : rawData) {
            if      (item instanceof Integer i) numericSum  += i;
            else if (item instanceof Double  d) numericSum  += d;
            else if (item instanceof String  s) upperStrings.add(s.toUpperCase());
            else if (item instanceof List<?> l) flattened.addAll(l);
            else if (item == null)             nullCount++;
        }

        System.out.println("=== DATA PIPELINE RESULTS ===");
        System.out.printf("Numeric Sum:     %.2f%n", numericSum);
        System.out.println("Upper Strings:   " + upperStrings);
        System.out.println("Flattened Lists: " + flattened);
        System.out.println("Null Count:      " + nullCount);
        System.out.println("Processed:       " + rawData.length + " items");
    }
}
▶ Output
=== DATA PIPELINE RESULTS === Numeric Sum: 164.84 Upper Strings: [HELLO, WORLD, JAVA, BACKEND] Flattened Lists: [a, b, 1, 2, 3] Null Count: 2 Processed: 14 items

⚠️ Common Mistakes — Inhe Hamesha Avoid Karo

Incorrect Order in if-else Chain: if (obj instanceof Animal) pehle check karoge, phir instanceof Dog kabhi reach nahi hoga! Hamesha most specific (child) type pehle check karo, phir parent. Dog → Animal → Object order mein.
instanceof ke Baad Bhi Galat Cast: if (obj instanceof Animal) { Dog d = (Dog) obj; } — ClassCastException! instanceof Animal se sirf Animal cast safe hai. Hamesha exactly us type se cast karo jo check kiya tha.
⚠️
instanceof Primitive Types Par Nahi Kaam Karta: 5 instanceof int — COMPILE ERROR. instanceof sirf reference types (objects) ke liye hai. Primitives int, double etc. pe use nahi hota. Use Integer, Double (wrapper classes) instead.
⚠️
Right Side Variable Nahi Ho Sakta: obj instanceof someVariable — COMPILE ERROR. Right side mein hamesha class/interface ka naam hona chahiye, variable nahi. Ye compile-time ke type information ke liye hai.
Pattern Matching Variable Scope: Java 16+ mein if (obj instanceof String s) { ... }s sirf if block ke andar accessible hai. Else block mein nahi. if (!(obj instanceof String s)) { return; } s.length() — ye valid hai because after return, s guaranteed accessible hai.
💡
instanceof vs getClass() — Always Remember: instanceof hierarchy check karta hai (is-a). getClass() == exact class check karta hai. dog instanceof Animal = true. dog.getClass() == Animal.class = false. Correct choice depends on whether you want subtype matches or exact matches.
🎯
Use Polymorphism When Possible: Agar instanceof chain 3+ types cover kare aur aap khud code likhte ho, consider abstract/interface method use karna. instanceof best hai jab: third-party classes, equals(), null-safe checks, capability detection. Long chains = code smell → refactor to polymorphism.