Operator kya hai, memory mein kaise kaam karta hai, type checking, polymorphism, pattern matching (Java 16+) — sab kuch ek hi jagah, depth mein.
Complete Theory · JVM Internal · Type Hierarchy · Why It Exists · Use Cases
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.
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.
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:
false return karo immediatelytrue, nahi to falseYe check O(depth of hierarchy) time leta hai — typically very fast (microseconds). JIT compiler aksar ise inline bhi kar deta hai.
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.
Actual type ki jaanch runtime pe hoti hai — JVM ke type descriptor se.
Puri class chain check karta hai — superclass, interface, sab include hain.
null instanceof X hamesha false — koi NullPointerException nahi aati.
Hamesha true ya false return karta hai — koi exception nahi.
Classes ke alawa interfaces bhi check kar sakta hai — obj instanceof Comparable.
Java 16+ mein instanceof + variable declare ek line mein — if (x instanceof Dog d).
if (e instanceof IOException)Syntax Rules · Downcasting · ClassCastException Prevention · Truth Table
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.
Object objif obj instanceof DogDog d = (Dog)objd.bark()| Expression | Object Created | Result | Reason |
|---|---|---|---|
dog instanceof Dog | new Dog() | true | Same class |
dog instanceof Animal | new Dog() | true | Dog is-a Animal (superclass) |
dog instanceof Object | new Dog() | true | All objects extend Object |
dog instanceof Cat | new Dog() | false | No Dog-Cat relationship |
animal instanceof Dog | new Animal() | false | Animal is NOT Dog (parent ≠ child) |
animal instanceof Dog | new Dog() | true | Runtime type is Dog, not Animal |
null instanceof Dog | null | false | null is never an instance of anything |
null instanceof Object | null | false | null ka koi runtime type nahi |
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
}
}
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.");
}
}
}
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);
}
}
Multi-level Hierarchy · Abstract Classes · equals() Method · Object Class
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.
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();
}
}
}
}
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
}
}
Interface Checking · Multiple Interfaces · Marker Interfaces · Comparable
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.
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);
}
}
}
null instanceof · NullPointerException Prevention · Null Safety Patterns
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.
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.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);
}
}
instanceof + Variable Declaration · JEP 394 · Switch Pattern (Java 21+) · Cleaner Code
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 castNew 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.
case Dog d -> likha ja sakta hai!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");
}
}
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);
}
}
Runtime Polymorphism · Visitor Pattern · Event Systems · Mixed Collections
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.
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);
}
}
When NOT to Use · Alternatives · getClass() vs instanceof · Performance
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).
equals() method mein — standard Java patternpublic 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!");
}
}
}
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());
}
}
Topic-wise 4-5 Problems Each · Click to See Solution
Fundamentals solid karo — hierarchy, interfaces, null
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));
}
}
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());
}
}
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");
}
}
}
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);
}
}
Real-world class hierarchies, equals(), pattern matching
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);
}
}
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]");
}
}
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);
}
}
Exception handling, data pipelines, equals() correctness
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);
}
}
}
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");
}
}
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.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.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.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.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 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.