User-Defined Type Casting — Upcasting · Downcasting · instanceof — Complete Revision Guide (Hinglish)
Condition: Casting tabhi possible hai jab extends ya implements relationship HO!
class Dog extends Animal { } → relationship hai → casting valid!
class Cat { } → Dog se koi relation nahi → (Cat) dog → ERROR!
Most Important Rule: OBJECT NAHI BADLA — sirf reference type badla! Same memory address, different reference.
"Dog IS-A Animal" → hamesha true! Isliye Java automatically allow karta hai — koi explicit cast operator nahi chahiye.
After upcasting:
• a.eat() → ✅ Animal method accessible
• a.bark() → ❌ ERROR! Animal reference bark() nahi jaanta — even though actual object Dog hai!
• a.describe() → ✅ Dog ka version chala (Overriding!)
Golden Rule: Reference type decide karta hai kaunse methods accessible hain. Actual object type decide karta hai kaunsa version chalega.
public class Upcasting1 { static class Animal { String name; Animal(String name) { this.name = name; } void eat() { System.out.println(name + " is eating"); } void breathe() { System.out.println(name + " is breathing"); } void describe() { System.out.println("I am an Animal: " + name); } } static class Dog extends Animal { String breed; Dog(String name, String breed) { super(name); this.breed = breed; } void bark() { System.out.println(name + " says: Woof!"); } void fetch() { System.out.println(name + " fetches the ball!"); } void describe() { System.out.println("I am a Dog: " + name + " (" + breed + ")"); } } public static void main(String[] args) { Dog dog = new Dog("Tommy", "Labrador"); System.out.println("--- Dog reference ---"); dog.eat(); dog.bark(); // ✅ Dog method accessible dog.fetch(); // ✅ Dog method accessible dog.describe(); System.out.println("\n--- Upcasting: Animal a = dog ---"); // UPCASTING - implicit, no cast operator needed! Animal a = dog; // same object, Animal reference now! a.eat(); // ✅ Animal method a.breathe(); // ✅ Animal method // a.bark(); // ❌ ERROR! Animal ref nahi jaanta bark() // a.fetch(); // ❌ ERROR! Animal ref nahi jaanta fetch() a.describe(); // ✅ calls Dog's describe! (Overriding!) System.out.println("\n--- Same object? ---"); System.out.println("dog == a : " + (dog == a)); // TRUE! Same memory address! System.out.println("\n--- Direct upcasting ---"); Animal a2 = new Dog("Bruno", "German Shepherd"); a2.eat(); a2.describe(); // Dog's version (overriding!) // a2.bark(); // ❌ not accessible through Animal ref } }
--- Dog reference --- Tommy is eating Tommy says: Woof! Tommy fetches the ball! I am a Dog: Tommy (Labrador) --- Upcasting: Animal a = dog --- Tommy is eating Tommy is breathing I am a Dog: Tommy (Labrador) --- Same object? --- dog == a : true --- Direct upcasting --- Bruno is eating I am a Dog: Bruno (German Shepherd)
Animal a = dog — same object, sirf reference type badla! a.bark() error dega — Animal reference bark() nahi jaanta. But a.describe() → Dog ka describe chala — kyunki runtime pe actual object Dog hai! dog == a → true — same memory address! Yahi polymorphism ka base hai!
public class Upcasting2 { static class Shape { String color; Shape(String color) { this.color = color; } double getArea() { return 0; } void display() { System.out.printf("%-12s color=%-8s area=%.2f%n", getClass().getSimpleName(), color, getArea()); } } static class Circle extends Shape { double radius; Circle(String color, double radius) { super(color); this.radius = radius; } double getArea() { return Math.PI * radius * radius; } } static class Rectangle extends Shape { double length, width; Rectangle(String color, double l, double w) { super(color); this.length = l; this.width = w; } double getArea() { return length * width; } } static class Triangle extends Shape { double base, height; Triangle(String color, double b, double h) { super(color); this.base = b; this.height = h; } double getArea() { return 0.5 * base * height; } } // Upcasting in method parameter! static void printShape(Shape s) { s.display(); // s can be ANY child object! } static double totalArea(Shape[] shapes) { double total = 0; for (Shape s : shapes) { total += s.getArea(); // each calls own getArea()! } return total; } public static void main(String[] args) { // UPCASTING - all stored as Shape! Shape[] shapes = { new Circle("Red", 5), // upcast! new Rectangle("Blue", 8, 4), // upcast! new Triangle("Green", 6, 3), // upcast! new Circle("Yellow", 3), // upcast! new Rectangle("Pink", 5, 5) // upcast! }; for (Shape s : shapes) { printShape(s); // each calls its own display/getArea! } System.out.printf("%nTotal Area: %.2f%n", totalArea(shapes)); } }
Circle color=Red area=78.54 Rectangle color=Blue area=32.00 Triangle color=Green area=9.00 Circle color=Yellow area=28.27 Rectangle color=Pink area=25.00 Total Area: 172.81
Shape[] array mein Circle, Rectangle, Triangle sab — yahi upcasting ki real power hai! totalArea(Shape[]) ek method har type handle karta hai. Runtime pe har object apna getArea() call karta hai. One array holds ALL types — yahi polymorphism hai!
public class Upcasting3 { interface Payable { double getAmount(); void processPayment(); } static class CreditCard implements Payable { String cardNo; double amount; CreditCard(String cardNo, double amount) { this.cardNo = cardNo; this.amount = amount; } public double getAmount() { return amount; } public void processPayment() { System.out.println("[CREDIT] Card: " + cardNo.substring(0,4) + "****" + " Amount: Rs." + amount); } void applyRewards() { System.out.println("Rewards: " + (amount * 0.02) + " points!"); } } static class UPI implements Payable { String upiId; double amount; UPI(String upiId, double amount) { this.upiId = upiId; this.amount = amount; } public double getAmount() { return amount; } public void processPayment() { System.out.println("[UPI] ID: " + upiId + " Amount: Rs." + amount); } } static class Cash implements Payable { double amount; Cash(double amount) { this.amount = amount; } public double getAmount() { return amount; } public void processPayment() { System.out.println("[CASH] Amount: Rs." + amount); } } // Upcasting → accepts ANY Payable! static void checkout(Payable payment) { System.out.println("Processing payment..."); payment.processPayment(); System.out.println("Amount: Rs." + payment.getAmount()); System.out.println("Done!\n"); } public static void main(String[] args) { // UPCASTING to interface type! Payable p1 = new CreditCard("4567890123456789", 1500); Payable p2 = new UPI("rahul@upi", 800); Payable p3 = new Cash(500); checkout(p1); checkout(p2); checkout(p3); // p1.applyRewards(); ← ERROR! Payable ref nahi jaanta Payable[] payments = { p1, p2, p3 }; double total = 0; for (Payable p : payments) total += p.getAmount(); System.out.println("Total: Rs." + total); } }
Processing payment... [CREDIT] Card: 4567**** Amount: Rs.1500.0 Amount: Rs.1500.0 Done! Processing payment... [UPI] ID: rahul@upi Amount: Rs.800.0 Amount: Rs.800.0 Done! Processing payment... [CASH] Amount: Rs.500.0 Amount: Rs.500.0 Done! Total: Rs.2800.0
Payable p1 = new CreditCard(...) — CreditCard upcast hua Payable mein. checkout(Payable payment) method CreditCard, UPI, Cash — teeno handle karta hai. Interface upcasting = class upcasting jaise hi kaam karta hai!
public class Upcasting4 { static class Employee { String name; double salary; Employee(String name, double salary) { this.name = name; this.salary = salary; } void work() { System.out.println(name + " is working"); } void getSalary() { System.out.println(name + " salary: Rs." + salary); } void introduce() { System.out.println("[Employee] I am " + name); } } static class Developer extends Employee { String language; int experience; Developer(String name, double salary, String lang, int exp) { super(name, salary); this.language = lang; this.experience = exp; } void code() { System.out.println(name + " coding in " + language); } void debug() { System.out.println(name + " debugging..."); } void introduce() { // Override! System.out.println("[Developer] I am " + name + ", " + experience + " yrs exp"); } } public static void main(String[] args) { Developer dev = new Developer("Rahul", 80000, "Java", 3); System.out.println("--- Developer reference ---"); dev.work(); dev.getSalary(); dev.introduce(); // Developer's version dev.code(); // ✅ accessible dev.debug(); // ✅ accessible System.out.println("\n--- After Upcasting ---"); Employee emp = dev; // UPCAST! emp.work(); // ✅ Employee method emp.getSalary(); // ✅ Employee method emp.introduce(); // ✅ Developer's version! (overriding) // emp.code(); // ❌ ERROR! Employee ref nahi jaanta code() // emp.debug(); // ❌ ERROR! Employee ref nahi jaanta debug() // emp.language; // ❌ ERROR! Employee ref nahi jaanta language field System.out.println("\n--- Runtime type check ---"); System.out.println("emp instanceof Developer? " + (emp instanceof Developer)); // true! System.out.println("emp instanceof Employee? " + (emp instanceof Employee)); // true! } }
--- Developer reference --- Rahul is working Rahul salary: Rs.80000.0 [Developer] I am Rahul, 3 yrs exp Rahul coding in Java Rahul debugging... --- After Upcasting --- Rahul is working Rahul salary: Rs.80000.0 [Developer] I am Rahul, 3 yrs exp --- Runtime type check --- emp instanceof Developer? true emp instanceof Employee? true
emp.code() ERROR — Employee reference code() nahi jaanta. But emp.introduce() → Developer ka version chala — kyunki actual object Developer hai! Reference type = kaunse methods accessible. Actual object = kaunsa version runs! Ye rule hamesha yaad rakho!
Compiler nahi jaanta actual object kaunsa hai! Animal a mein Dog bhi ho sakta hai, Cat bhi — compiler ke paas yeh info nahi hoti.
Programmer ki RESPONSIBILITY hai ensure karna ki cast sahi hai. Isliye explicit cast operator lagana padta hai.
Wrong cast → ClassCastException at RUNTIME:
Animal a = new Cat();
Dog d = (Dog) a; → ❌ ClassCastException! Cat Dog nahi ban sakta!
Safe Pattern: if (a instanceof Dog) { Dog d = (Dog) a; d.bark(); }
public class Downcasting1 { static class Animal { String name; Animal(String name) { this.name = name; } void eat() { System.out.println(name + " eating"); } void describe() { System.out.println("Animal: " + name); } } static class Dog extends Animal { String breed; Dog(String name, String breed) { super(name); this.breed = breed; } void bark() { System.out.println(name + ": Woof!"); } void fetch() { System.out.println(name + " fetches!"); } void describe() { System.out.println("Dog: " + name + " breed=" + breed); } } static class Cat extends Animal { boolean indoor; Cat(String name, boolean indoor) { super(name); this.indoor = indoor; } void meow() { System.out.println(name + ": Meow!"); } void purr() { System.out.println(name + " purring"); } void describe() { System.out.println("Cat: " + name + " indoor=" + indoor); } } public static void main(String[] args) { // STEP 1: Upcast Animal a = new Dog("Tommy", "Labrador"); a.eat(); a.describe(); // Dog's version // a.bark(); ← ERROR! Not accessible // STEP 2: Downcast System.out.println("\n--- Downcast to Dog ---"); Dog d = (Dog) a; // explicit cast! d.eat(); // Animal method d.bark(); // ✅ NOW accessible! d.fetch(); // ✅ NOW accessible! // STEP 3: instanceof check - SAFE downcast System.out.println("\n--- Safe downcast with instanceof ---"); Animal[] animals = { new Dog("Bruno", "German Shepherd"), new Cat("Whiskers", true), new Dog("Max", "Poodle"), new Cat("Luna", false) }; for (Animal animal : animals) { animal.describe(); // polymorphism if (animal instanceof Dog) { Dog dog = (Dog) animal; // safe downcast dog.bark(); } else if (animal instanceof Cat) { Cat cat = (Cat) animal; // safe downcast cat.meow(); } System.out.println(); } } }
Tommy eating Dog: Tommy breed=Labrador --- Downcast to Dog --- Tommy eating Tommy: Woof! Tommy fetches! --- Safe downcast with instanceof --- Dog: Bruno breed=German Shepherd Bruno: Woof! Cat: Whiskers indoor=true Whiskers: Meow! Dog: Max breed=Poodle Max: Woof! Cat: Luna indoor=false Luna: Meow!
Dog d = (Dog) a — explicit cast se Dog methods accessible ho gaye! instanceof check se safe downcast — pehle verify karo object Dog hai ya Cat, phir cast karo. Bina check ke cast karo aur object Cat ho → ClassCastException!
public class Downcasting2 { static class Vehicle { String brand; Vehicle(String brand) { this.brand = brand; } void start() { System.out.println(brand + " start"); } } static class Car extends Vehicle { int doors; Car(String brand, int doors) { super(brand); this.doors = doors; } void honk() { System.out.println(brand + ": Beep!"); } } static class Truck extends Vehicle { double payload; Truck(String brand, double payload) { super(brand); this.payload = payload; } void loadCargo() { System.out.println(brand + " loading " + payload + " tons"); } } public static void main(String[] args) { // SAFE downcast Vehicle v1 = new Car("Toyota", 4); // upcast if (v1 instanceof Car) { Car c = (Car) v1; // safe! c.honk(); System.out.println("Doors: " + c.doors); } // UNSAFE downcast → ClassCastException! Vehicle v2 = new Truck("Tata", 10.0); // Truck object! System.out.println("Is v2 a Car? " + (v2 instanceof Car)); // FALSE! System.out.println("Is v2 a Truck? " + (v2 instanceof Truck)); // TRUE! // Try wrong cast: try { Car wrongCast = (Car) v2; // ← RUNTIME ERROR! wrongCast.honk(); } catch (ClassCastException e) { System.out.println("ERROR: " + e.getMessage()); System.out.println("Truck cannot be cast to Car!"); } // Correct cast: if (v2 instanceof Truck) { Truck t = (Truck) v2; // safe! t.loadCargo(); } } }
Toyota: Beep! Doors: 4 Is v2 a Car? false Is v2 a Truck? true ERROR: class Downcasting2$Truck cannot be cast to class Downcasting2$Car Truck cannot be cast to Car! Tata loading 10.0 tons
v2 actually Truck object hai — (Car) v2 try kiya → ClassCastException! Truck Car nahi ban sakta — koi IS-A relation nahi. instanceof se pehle check karo — ALWAYS use instanceof before downcast — ye golden rule hai!
public class Downcasting3 { static class Employee { String name; double salary; Employee(String n, double s) { name = n; salary = s; } void work() { System.out.println(name + " working..."); } double calculateBonus() { return salary * 0.10; } } static class Developer extends Employee { String language; Developer(String n, double s, String lang) { super(n, s); this.language = lang; } void code() { System.out.println(name + " coding " + language); } double calculateBonus() { return salary * 0.20; } // 20% void deployApp() { System.out.println(name + " deploying app!"); } } static class Manager extends Employee { int teamSize; Manager(String n, double s, int t) { super(n, s); this.teamSize = t; } void conductMeeting() { System.out.println(name + " meeting with " + teamSize + " people"); } double calculateBonus() { return salary * 0.30; } // 30% } // Upcast in parameter → Downcast inside for specific methods static void processEmployee(Employee emp) { emp.work(); System.out.printf("Bonus: Rs.%.0f%n", emp.calculateBonus()); if (emp instanceof Developer) { Developer dev = (Developer) emp; // downcast! dev.code(); dev.deployApp(); } else if (emp instanceof Manager) { Manager mgr = (Manager) emp; // downcast! mgr.conductMeeting(); } } public static void main(String[] args) { // Upcast in array Employee[] team = { new Developer("Rahul", 80000, "Java"), new Manager("Priya", 120000, 8), new Developer("Amit", 75000, "Python"), new Manager("Sunita", 110000, 5) }; for (Employee emp : team) { System.out.println("--- " + emp.name + " ---"); processEmployee(emp); System.out.println(); } double totalBonus = 0; for (Employee emp : team) totalBonus += emp.calculateBonus(); System.out.printf("Total Bonus: Rs.%.0f%n", totalBonus); } }
--- Rahul --- Rahul working... Bonus: Rs.16000 Rahul coding Java Rahul deploying app! --- Priya --- Priya working... Bonus: Rs.36000 Priya meeting with 8 people --- Amit --- Amit working... Bonus: Rs.15000 Amit coding Python Amit deploying app! --- Sunita --- Sunita working... Bonus: Rs.33000 Sunita meeting with 5 people Total Bonus: Rs.100000
Employee[] array mein Developer aur Manager dono — upcasting! processEmployee(Employee emp) method mein instanceof + downcast se specific methods call kiye. Ek method sab handle karta hai — upcasting + downcasting ka perfect combination!
public class Downcasting4 { static class Animal { String name; Animal(String name) { this.name = name; } void describe() { System.out.println("Animal: " + name); } } static class Dog extends Animal { String breed; Dog(String n, String b) { super(n); breed = b; } void bark() { System.out.println(name + ": Woof!"); } void fetch() { System.out.println(name + " fetches"); } void describe() { System.out.println("Dog: "+name+" ("+breed+")"); } } static class Cat extends Animal { boolean indoor; Cat(String n, boolean i) { super(n); indoor = i; } void meow() { System.out.println(name + ": Meow!"); } void purr() { System.out.println(name + " purrs"); } void describe() { System.out.println("Cat: "+name+" indoor="+indoor); } } static class Bird extends Animal { boolean canFly; Bird(String n, boolean f) { super(n); canFly = f; } void chirp() { System.out.println(name + ": Tweet!"); } void fly() { System.out.println(name + (canFly ? " flying!" : " cannot fly!")); } void describe() { System.out.println("Bird: "+name+" canFly="+canFly); } } static void processOldWay(Animal animal) { animal.describe(); if (animal instanceof Dog) { Dog d = (Dog) animal; d.bark(); d.fetch(); } else if (animal instanceof Cat) { Cat c = (Cat) animal; c.meow(); } else if (animal instanceof Bird) { Bird b = (Bird) animal; b.chirp(); b.fly(); } } static void performAction(Animal animal) { System.out.print("Action: "); if (animal instanceof Dog) ((Dog)animal).bark(); else if (animal instanceof Cat) ((Cat)animal).meow(); else if (animal instanceof Bird) ((Bird)animal).chirp(); } public static void main(String[] args) { Animal[] animals = { new Dog("Tommy", "Labrador"), new Cat("Whiskers", true), new Bird("Tweety", true), new Bird("Penguin", false), new Cat("Luna", false) }; System.out.println("--- Full processing ---"); for (Animal a : animals) { processOldWay(a); System.out.println(); } System.out.println("--- Quick actions ---"); for (Animal a : animals) performAction(a); System.out.println("\n--- instanceof results ---"); Animal a = new Dog("Test", "Mixed"); System.out.println("instanceof Dog: " + (a instanceof Dog)); System.out.println("instanceof Cat: " + (a instanceof Cat)); System.out.println("instanceof Animal: " + (a instanceof Animal)); } }
--- Full processing --- Dog: Tommy (Labrador) Tommy: Woof! Tommy fetches Cat: Whiskers indoor=true Whiskers: Meow! Bird: Tweety canFly=true Tweety: Tweet! Tweety flying! Bird: Penguin canFly=false Penguin: Tweet! Penguin cannot fly! Cat: Luna indoor=false Luna: Meow! --- Quick actions --- Action: Tommy: Woof! Action: Whiskers: Meow! Action: Tweety: Tweet! Action: Penguin: Tweet! Action: Luna: Meow! --- instanceof results --- instanceof Dog: true instanceof Cat: false instanceof Animal: true
instanceof chain se Dog, Cat, Bird sab alag-alag handle ho rahe hain. instanceof Dog → true, instanceof Cat → false, instanceof Animal → true — Dog IS-A Animal, isliye Animal bhi true hai! Inline cast ((Dog)animal).bark() — cast karke usi line pe method call!
public class Downcasting5 { static class Account { String accNo, holder; double balance; Account(String accNo, String holder, double balance) { this.accNo = accNo; this.holder = holder; this.balance = balance; } void deposit(double amount) { balance += amount; System.out.printf("[DEPOSIT] +Rs.%.0f → Rs.%.0f%n", amount, balance); } double getBalance() { return balance; } void displayInfo() { System.out.printf("%-12s %-15s Rs.%.0f%n", accNo, holder, balance); } } static class SavingsAccount extends Account { double interestRate; SavingsAccount(String accNo, String holder, double balance, double rate) { super(accNo, holder, balance); this.interestRate = rate; } void addInterest() { double interest = balance * interestRate / 100; balance += interest; System.out.printf("[INTEREST @%.1f%%] +Rs.%.2f%n", interestRate, interest); } void withdraw(double amount) { if (balance - amount >= 500) { balance -= amount; System.out.printf("[WITHDRAW] -Rs.%.0f → Rs.%.0f%n", amount, balance); } else { System.out.println("Min balance Rs.500 required!"); } } } static class LoanAccount extends Account { double loanAmount, emiAmount; int remainingEmis; LoanAccount(String accNo, String holder, double loan, double emi, int emis) { super(accNo, holder, 0); loanAmount = loan; emiAmount = emi; remainingEmis = emis; } void payEMI() { if (remainingEmis > 0) { remainingEmis--; System.out.printf("[EMI PAID] Rs.%.0f | Remaining: %d%n", emiAmount, remainingEmis); } else { System.out.println("Loan fully paid!"); } } double getRemainingLoan() { return emiAmount * remainingEmis; } } // Upcast in array — all stored as Account! static Account[] bankAccounts = { new SavingsAccount("SB001", "Rahul", 50000, 6.5), new LoanAccount("LN001", "Priya", 500000, 15000, 36), new SavingsAccount("SB002", "Amit", 30000, 5.0), new LoanAccount("LN002", "Sunita", 200000, 8000, 24) }; static void monthlyProcess() { System.out.println("\n=== Monthly Processing ==="); for (Account acc : bankAccounts) { System.out.println("Processing: " + acc.holder); // Downcast to call specific methods! if (acc instanceof SavingsAccount) { SavingsAccount sa = (SavingsAccount) acc; sa.addInterest(); // savings specific } else if (acc instanceof LoanAccount) { LoanAccount la = (LoanAccount) acc; la.payEMI(); // loan specific } } } static void displayAll() { System.out.println("\n=== All Accounts ==="); System.out.printf("%-12s %-15s %-12s %-10s%n", "AccNo", "Holder", "Balance", "Type"); System.out.println("-".repeat(50)); for (Account acc : bankAccounts) { String type = (acc instanceof SavingsAccount) ? "SAVINGS" : "LOAN"; System.out.printf("%-12s %-15s Rs.%-9.0f %-10s%n", acc.accNo, acc.holder, acc.balance, type); if (acc instanceof LoanAccount) { LoanAccount la = (LoanAccount) acc; System.out.printf(" └ Remaining Loan: Rs.%.0f%n", la.getRemainingLoan()); } } } public static void main(String[] args) { displayAll(); monthlyProcess(); monthlyProcess(); displayAll(); } }
=== All Accounts === AccNo Holder Balance Type -------------------------------------------------- SB001 Rahul Rs.50000 SAVINGS LN001 Priya Rs.0 LOAN └ Remaining Loan: Rs.540000 SB002 Amit Rs.30000 SAVINGS LN002 Sunita Rs.0 LOAN └ Remaining Loan: Rs.192000 === Monthly Processing === Processing: Rahul [INTEREST @6.5%] +Rs.3250.00 Processing: Priya [EMI PAID] Rs.15000 | Remaining: 35 Processing: Amit [INTEREST @5.0%] +Rs.1500.00 Processing: Sunita [EMI PAID] Rs.8000 | Remaining: 23 === Monthly Processing === Processing: Rahul [INTEREST @6.5%] +Rs.3462.50 Processing: Priya [EMI PAID] Rs.15000 | Remaining: 34 Processing: Amit [INTEREST @5.0%] +Rs.1575.00 Processing: Sunita [EMI PAID] Rs.8000 | Remaining: 22 === All Accounts === AccNo Holder Balance Type -------------------------------------------------- SB001 Rahul Rs.56712 SAVINGS LN001 Priya Rs.0 LOAN └ Remaining Loan: Rs.510000 SB002 Amit Rs.32075 SAVINGS LN002 Sunita Rs.0 LOAN └ Remaining Loan: Rs.176000
Account[] mein SavingsAccount aur LoanAccount dono — upcasting! Monthly processing mein instanceof + downcast se specific methods call: savings pe interest, loan pe EMI. Ek loop, ek method — sab kuch handle! Real-world casting ka perfect example.
| Type | Direction | Kaise | Accessible Methods | Risk |
|---|---|---|---|---|
| Upcasting | Child → Parent | ✓ Implicit (automatic) | Only parent methods | ✓ No risk — always safe |
| Downcasting | Parent → Child | (ChildType) ref — Explicit |
All child methods! | ✗ ClassCastException possible |
| instanceof | Runtime check | obj instanceof Type |
— | ✓ Safe — returns true/false |
| Overriding + Upcast | Runtime poly | Automatic | Child version runs! | ✓ No risk |
Rule 1: Reference type → KAUNSE methods accessible hain (compile-time decision)
Rule 2: Actual object type → KAUNSA version chalega (runtime decision = polymorphism)
Rule 3: ALWAYS use instanceof before downcasting → ClassCastException se bachao!
Rule 4: Object kabhi nahi badlata — sirf reference type badlata hai!
Rule 5: Casting tabhi valid hai jab extends/implements relationship ho!
| Mistake | Wrong ❌ | Sahi ✅ |
|---|---|---|
| Downcast without check | Dog d = (Dog) animal; |
if(animal instanceof Dog) Dog d=(Dog)animal; |
| Unrelated cast | Dog d = (Cat) animal; |
extends/implements relation ZAROORI hai |
| Object badal gaya | Think karo upcast kiya to object badla | Object same rahta hai! Sirf reference badla |
| Missing explicit cast | Dog d = animal; |
Dog d = (Dog) animal; |
| Child method via parent ref | animalRef.bark(); |
Pehle downcast karo, phir call karo |
Animal a = new Dog() ya Animal a = new Cat(). Compiler nahi jaanta actual type kya hai! Programmer ki responsibility hai — isliye explicit cast likhna padta hai.Animal a = new Cat();Dog d = (Dog) a; → ClassCastException!Animal a = new Dog();a instanceof Dog → TRUE (actual object Dog hai)a instanceof Animal → TRUE (Dog IS-A Animal)a instanceof Cat → FALSE (actual object Cat nahi)
Animal a = new Dog();a.sound() → Dog's sound() runs! Reference type Animal hai, but actual object Dog hai — actual object ka version chalega.
dog == a → true — same heap location! Ye ek bahut common misconception hai.if (animal instanceof Dog) { Dog d = (Dog) animal; d.bark();}