β˜• Java Class & Object

Complete Deep Revision Guide β€” Backend Course ke liye

πŸ”΅ Topic 1: Class & Object Basics

🧠 Memory Mein Kaise Kaam Karta Hai?

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         CLASS (Blueprint)    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ ClassName {         β”‚    β”‚
β”‚  β”‚   - fields (data)   β”‚    β”‚
β”‚  β”‚   - methods (code)  β”‚    β”‚
β”‚  β”‚ }                   β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚  ⚠️ Class = NO MEMORY ALLOC β”‚
β”‚  ⚠️ Sirf TEMPLATE hai!      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              ↓ new keyword
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚        OBJECT (Instance)     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ [Heap Memory]       β”‚    β”‚
β”‚  β”‚ β€’ fields β†’ values   β”‚    β”‚
β”‚  β”‚ β€’ methods β†’ code refβ”‚    β”‚
β”‚  β”‚ β€’ reference var β†’   β”‚    β”‚
β”‚  β”‚   Stack mein store  β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚  βœ… Object = MEMORY ALLOC   β”‚
β”‚  βœ… Real data store hota haiβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Class = Blueprint/Template | Object = Us blueprint se bana hua actual ghar

πŸ“ ClassObject1.java Basic Class & Object Creation
// Class define karna - ye sirf blueprint hai
class Student {
    // Fields/Attributes (Instance Variables)
    String name;
    int rollNo;
    double marks;
    
    // Method/Behavior
    void displayInfo() {
        System.out.println("Name: " + name);
        System.out.println("Roll: " + rollNo);
        System.out.println("Marks: " + marks);
    }
}

public class ClassObject1 {
    public static void main(String[] args) {
        
        // Object create karna - Heap memory allocate hoti hai
        Student s1 = new Student();  // s1 β†’ reference variable (Stack)
        
        // Fields ko value assign karna
        s1.name = "Rahul";
        s1.rollNo = 101;
        s1.marks = 85.5;
        
        // Method call karna
        s1.displayInfo();
        
        // Second object - alag memory location!
        Student s2 = new Student();
        s2.name = "Priya";
        s2.rollNo = 102;
        s2.marks = 92.0;
        s2.displayInfo();
    }
}
β–Ά OUTPUT
Name: Rahul
Roll: 101
Marks: 85.5
Name: Priya
Roll: 102
Marks: 92.0
πŸ’‘ Memory Map: s1 aur s2 alag-alag objects hain! Heap mein do different memory blocks bante hain. Reference variable Stack mein rehta hai jo Heap address point karta hai.
πŸ“ ClassObject2.java Multiple Objects & Null Reference
class Book {
    String title;
    String author;
    int pages;
    
    void showDetails() {
        System.out.println(title + " by " + author + " (" + pages + " pages)");
    }
}

public class ClassObject2 {
    public static void main(String[] args) {
        
        // Reference variable declare kiya, par object nahi banaya
        Book b1;  // b1 = null (default value)
        
        // b1.showDetails(); ❌ NullPointerException dega!
        
        // Ab object create karte hain
        b1 = new Book();
        b1.title = "Java Complete Reference";
        b1.author = "Herbert Schildt";
        b1.pages = 1200;
        b1.showDetails();
        
        // Array of Objects
        Book[] library = new Book[3];  // 3 references, sab null
        
        library[0] = new Book();
        library[0].title = "Effective Java";
        library[0].author = "Joshua Bloch";
        library[0].pages = 416;
        
        library[1] = new Book();
        library[1].title = "Head First Java";
        library[1].author = "Kathy Sierra";
        library[1].pages = 720;
        
        // library[2] abhi bhi null hai!
        
        System.out.println("\nLibrary Contents:");
        for(int i = 0; i < library.length; i++) {
            if(library[i] != null) {
                library[i].showDetails();
            } else {
                System.out.println("Slot " + i + " is empty (null)");
            }
        }
    }
}
β–Ά OUTPUT
Java Complete Reference by Herbert Schildt (1200 pages)

Library Contents:
Effective Java by Joshua Bloch (416 pages)
Head First Java by Kathy Sierra (720 pages)
Slot 2 is empty (null)
πŸ’‘ Important: Array of Objects mein sirf references create hote hain, actual objects nahi! Har index pe alag se new karna padta hai.
πŸ“ ClassObject3.java Object Reference Copy vs New Object
class Account {
    String accNo;
    double balance;
    
    void deposit(double amount) {
        balance += amount;
        System.out.println("Deposited: " + amount + ", New Balance: " + balance);
    }
}

public class ClassObject3 {
    public static void main(String[] args) {
        
        Account acc1 = new Account();
        acc1.accNo = "ACC001";
        acc1.balance = 1000;
        
        // Reference copy - SAME object, alag reference variable
        Account acc2 = acc1;  // acc2 bhi same heap location point kar raha!
        
        System.out.println("Before: acc1.balance = " + acc1.balance);
        acc2.deposit(500);  // acc2 se call kiya
        System.out.println("After: acc1.balance = " + acc1.balance);  
        // ^ acc1 bhi change ho gaya! Kyunki SAME object hai
        
        System.out.println("\nacc1 == acc2: " + (acc1 == acc2));  // true!
        
        // NEW object create karna - alag memory
        Account acc3 = new Account();
        acc3.accNo = "ACC002";
        acc3.balance = 2000;
        
        System.out.println("\nacc1 == acc3: " + (acc1 == acc3));  // false!
        acc3.deposit(300);
        System.out.println("acc1.balance: " + acc1.balance);  // unchanged
        System.out.println("acc3.balance: " + acc3.balance);  // changed
    }
}
β–Ά OUTPUT
Before: acc1.balance = 1000.0
Deposited: 500.0, New Balance: 1500.0
After: acc1.balance = 1500.0

acc1 == acc2: true

acc1 == acc3: false
Deposited: 300.0, New Balance: 2300.0
acc1.balance: 1500.0
acc3.balance: 2300.0
πŸ’‘ Golden Rule: Account acc2 = acc1; β†’ Object COPY nahi hota! Sirf reference copy hota hai. Dono variables SAME object ko point karte hain. New object ke liye new keyword zaroori hai!
πŸ“ ClassObject4.java Primitive vs Object Parameter Passing
class Data {
    int value;
    
    Data(int v) { value = v; }
}

public class ClassObject4 {
    
    // Primitive type parameter - PASS BY VALUE
    static void modifyPrimitive(int x) {
        x = x * 10;
        System.out.println("Inside method (primitive): " + x);
    }
    
    // Object reference parameter - PASS BY VALUE OF REFERENCE
    static void modifyObject(Data d) {
        d.value = d.value * 10;  // Original object modify!
        System.out.println("Inside method (object field): " + d.value);
    }
    
    // Object reference ko reassign karna
    static void reassignReference(Data d) {
        d = new Data(999);  // New object, local reference change
        System.out.println("Inside method (reassigned): " + d.value);
    }
    
    public static void main(String[] args) {
        
        // Primitive test
        int num = 5;
        System.out.println("Before primitive: " + num);
        modifyPrimitive(num);
        System.out.println("After primitive: " + num + " (unchanged!)");
        
        // Object field modify test
        Data obj = new Data(5);
        System.out.println("\nBefore object field: " + obj.value);
        modifyObject(obj);
        System.out.println("After object field: " + obj.value + " (CHANGED!)");
        
        // Reference reassign test
        Data obj2 = new Data(5);
        System.out.println("\nBefore reassign: " + obj2.value);
        reassignReference(obj2);
        System.out.println("After reassign: " + obj2.value + " (unchanged!)");
    }
}
β–Ά OUTPUT
Before primitive: 5
Inside method (primitive): 50
After primitive: 5 (unchanged!)

Before object field: 5
Inside method (object field): 50
After object field: 50 (CHANGED!)

Before reassign: 5
Inside method (reassigned): 999
After reassign: 5 (unchanged!)
πŸ’‘ Java is ALWAYS Pass-by-Value!
β€’ Primitive: Value ki copy pass hoti hai
β€’ Object: Reference ki VALUE copy hoti hai (reference ki copy, not reference itself)
β€’ Isliye object ke fields modify kar sakte hain, par reference reassign nahi affect karta original ko
πŸ“ ClassObject5.java Object Lifecycle & Garbage Collection
class Temp {
    String name;
    
    Temp(String n) { 
        name = n;
        System.out.println("🟒 Constructor: " + name + " created");
    }
    
    // Finalize - deprecated but for demo (GC se pehle call hota tha)
    protected void finalize() {
        System.out.println("πŸ”΄ Finalize: " + name + " being garbage collected");
    }
    
    void show() {
        System.out.println("Object: " + name);
    }
}

public class ClassObject5 {
    public static void main(String[] args) {
        
        // Object creation
        Temp t1 = new Temp("Alpha");
        t1.show();
        
        // Reference null karna - object eligible for GC
        t1 = null;  // "Alpha" object ab unreachable!
        System.out.println("t1 set to null - Alpha eligible for GC");
        
        // New object same reference variable mein
        t1 = new Temp("Beta");
        t1.show();
        
        // Scope ke bahar jaane par automatic GC eligible
        {
            Temp t2 = new Temp("Gamma");
            t2.show();
        }  // t2 scope khatam - Gamma eligible for GC
        System.out.println("t2 scope ended - Gamma eligible for GC");
        
        // GC suggest karna (guarantee nahi!)
        System.out.println("\nRequesting GC (no guarantee)...");
        System.gc();
        
        // Thoda wait for GC to potentially run
        try { Thread.sleep(100); } catch(Exception e) {}
        
        System.out.println("\nProgram ending...");
        // t1 ("Beta") bhi ab GC eligible hoga jab program end hoga
    }
}
β–Ά OUTPUT (GC timing may vary)
🟒 Constructor: Alpha created
Object: Alpha
t1 set to null - Alpha eligible for GC
🟒 Constructor: Beta created
Object: Beta
🟒 Constructor: Gamma created
Object: Gamma
t2 scope ended - Gamma eligible for GC

Requesting GC (no guarantee)...
πŸ”΄ Finalize: Alpha being garbage collected
πŸ”΄ Finalize: Gamma being garbage collected

Program ending...
πŸ’‘ Garbage Collection Points:
βœ… Object tab GC eligible hota hai jab koi reference usko point na kare
βœ… obj = null; β†’ explicit dereference
βœ… Scope ke bahar local references automatically disappear
βœ… System.gc() sirf suggestion hai, guarantee nahi
βœ… finalize() deprecated hai - use try-with-resources for cleanup

🟒 Topic 2: Constructors Deep Dive

🧠 Constructor Kya Hai? Memory Flow:

1. new ClassName() call hota hai
         ↓
2. Heap memory allocate hoti hai object ke liye
         ↓  
3. DEFAULT values assign hoti hain (0, null, false)
         ↓
4. CONSTRUCTOR execute hota hai β†’ custom initialization
         ↓
5. Reference variable ko heap address return hota hai

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Constructor Rules:          β”‚
β”‚ β€’ Name = Class name EXACT   β”‚
β”‚ β€’ NO return type (not even void)β”‚
β”‚ β€’ Automatically called with new β”‚
β”‚ β€’ Agar khud na likho β†’ Default constructor milta haiβ”‚
β”‚ β€’ Parameterized likha β†’ Default NAHI milta!      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
πŸ“ Constructor1.java Default & Parameterized Constructor
class Employee {
    String name;
    int id;
    double salary;
    
    // πŸ”Ή Default Constructor (No-arg)
    Employee() {
        System.out.println("πŸ“¦ Default constructor called");
        name = "Unknown";
        id = 0;
        salary = 0.0;
    }
    
    // πŸ”Ή Parameterized Constructor
    Employee(String n, int i, double s) {
        System.out.println("πŸ“¦ Parameterized constructor called");
        name = n;   // this.name = n; bhi likh sakte the
        id = i;
        salary = s;
    }
    
    void display() {
        System.out.println(name + " (ID:" + id + ") - β‚Ή" + salary);
    }
}

public class Constructor1 {
    public static void main(String[] args) {
        
        System.out.println("=== Creating with default constructor ===");
        Employee e1 = new Employee();  // Default constructor call
        e1.display();
        
        System.out.println("\n=== Creating with parameterized constructor ===");
        Employee e2 = new Employee("Amit", 101, 50000);  // Parameterized
        e2.display();
        
        System.out.println("\n=== Creating another with default ===");
        Employee e3 = new Employee();
        e3.name = "Priya";  // Manual assignment after default init
        e3.id = 102;
        e3.salary = 45000;
        e3.display();
    }
}
β–Ά OUTPUT
=== Creating with default constructor ===
πŸ“¦ Default constructor called
Unknown (ID:0) - β‚Ή0.0

=== Creating with parameterized constructor ===
πŸ“¦ Parameterized constructor called
Amit (ID:101) - β‚Ή50000.0

=== Creating another with default ===
πŸ“¦ Default constructor called
Priya (ID:102) - β‚Ή45000.0
πŸ“ Constructor2.java Constructor Overloading
class Rectangle {
    double length, width;
    
    // πŸ”Ή No-arg: Square with side 1
    Rectangle() {
        length = width = 1.0;
        System.out.println("⬜ Default: 1x1 square");
    }
    
    // πŸ”Ή Single param: Square with given side
    Rectangle(double side) {
        length = width = side;
        System.out.println("⬜ Square: " + side + "x" + side);
    }
    
    // πŸ”Ή Two params: Rectangle
    Rectangle(double l, double w) {
        length = l;
        width = w;
        System.out.println("β–­ Rectangle: " + l + "x" + w);
    }
    
    double area() {
        return length * width;
    }
}

public class Constructor2 {
    public static void main(String[] args) {
        
        Rectangle r1 = new Rectangle();           // Calls no-arg
        System.out.println("Area: " + r1.area() + "\n");
        
        Rectangle r2 = new Rectangle(5);          // Calls single-param
        System.out.println("Area: " + r2.area() + "\n");
        
        Rectangle r3 = new Rectangle(4, 6);       // Calls two-param
        System.out.println("Area: " + r3.area() + "\n");
        
        // Compiler decides which constructor based on arguments!
        // Ye hai Constructor Overloading
    }
}
β–Ά OUTPUT
⬜ Default: 1x1 square
Area: 1.0

⬜ Square: 5.0x5.0
Area: 25.0

β–­ Rectangle: 4.0x6.0
Area: 24.0
πŸ’‘ Constructor Overloading: Same class mein multiple constructors with DIFFERENT parameters. Compiler argument count/type dekhta hai aur sahi constructor choose karta hai. Return type nahi hota constructor ka!
πŸ“ Constructor3.java Constructor Chaining with this()
class Product {
    String name;
    int id;
    double price;
    String category;
    
    // πŸ”Ή Master constructor - saara kaam yahan
    Product(String n, int i, double p, String c) {
        System.out.println("πŸ”— Master constructor");
        name = n; id = i; price = p; category = c;
    }
    
    // πŸ”Ή 3-param β†’ master ko call
    Product(String n, int i, double p) {
        this(n, i, p, "General");  // this() must be FIRST line!
        System.out.println("πŸ”— 3-param constructor");
    }
    
    // πŸ”Ή 2-param β†’ 3-param ko call
    Product(String n, int i) {
        this(n, i, 0.0);  // Chain: 2β†’3β†’4 param
        System.out.println("πŸ”— 2-param constructor");
    }
    
    // πŸ”Ή No-arg β†’ 2-param ko call
    Product() {
        this("NoName", 0);
        System.out.println("πŸ”— No-arg constructor");
    }
    
    void show() {
        System.out.println(name + " #" + id + " β‚Ή" + price + " [" + category + "]");
    }
}

public class Constructor3 {
    public static void main(String[] args) {
        
        System.out.println("=== Chain: No-arg β†’ 2 β†’ 3 β†’ 4 ===");
        Product p1 = new Product();
        p1.show();
        
        System.out.println("\n=== Chain: 2-param β†’ 3 β†’ 4 ===");
        Product p2 = new Product("Laptop", 101);
        p2.show();
        
        System.out.println("\n=== Direct 4-param ===");
        Product p3 = new Product("Phone", 102, 25000, "Electronics");
        p3.show();
    }
}
β–Ά OUTPUT
=== Chain: No-arg β†’ 2 β†’ 3 β†’ 4 ===
πŸ”— Master constructor
πŸ”— 3-param constructor
πŸ”— 2-param constructor
πŸ”— No-arg constructor
NoName #0 β‚Ή0.0 [General]

=== Chain: 2-param β†’ 3 β†’ 4 ===
πŸ”— Master constructor
πŸ”— 3-param constructor
πŸ”— 2-param constructor
Laptop #101 β‚Ή0.0 [General]

=== Direct 4-param ===
πŸ”— Master constructor
Phone #102 β‚Ή25000.0 [Electronics]
πŸ’‘ Constructor Chaining Rules:
βœ… this(...) se dusre constructor call karo
βœ… this() MUST be FIRST statement in constructor
βœ… Circular chaining nahi kar sakte (Aβ†’Bβ†’A = compile error)
βœ… Code reuse hota hai - master constructor mein saara logic
πŸ“ Constructor4.java Default Constructor - Kab Milta Hai?
// πŸ”Ή Case 1: No constructor likha β†’ Compiler default deta hai
class Case1 {
    int x;
    // Compiler automatically adds: Case1() { super(); }
}

// πŸ”Ή Case 2: Khud parameterized likha β†’ Default NAHI milega!
class Case2 {
    int x;
    Case2(int val) { x = val; }
    // ❌ Ab Case2() constructor nahi hai!
    // new Case2(); β†’ Compile Error!
}

// πŸ”Ή Case 3: Khud default bhi likh do β†’ dono milenge
class Case3 {
    int x;
    
    Case3() { x = 0; System.out.println("Default"); }
    Case3(int val) { x = val; System.out.println("Param"); }
}

public class Constructor4 {
    public static void main(String[] args) {
        
        // Case 1: Default constructor available
        Case1 c1 = new Case1();  // βœ… Works
        System.out.println("Case1 x = " + c1.x);  // 0 (default int value)
        
        // Case 2: Only parameterized exists
        Case2 c2 = new Case2(100);  // βœ… Works
        System.out.println("Case2 x = " + c2.x);
        // Case2 c3 = new Case2(); ❌ Compile Error!
        
        // Case 3: Both constructors available
        Case3 c3a = new Case3();     // βœ… Default
        Case3 c3b = new Case3(200);  // βœ… Parameterized
    }
}
β–Ά OUTPUT
Case1 x = 0
Case2 x = 100
Default
Param
πŸ’‘ Default Constructor Golden Rule:
βœ… Agar tum KUCH bhi constructor nahi likhte β†’ Compiler default no-arg constructor deta hai
❌ Agar tum KOI BHI constructor likh dete ho β†’ Compiler default NAHI dega
βœ… Solution: Agar parameterized likha hai aur default bhi chahiye β†’ Khud likh do no-arg constructor!
πŸ“ Constructor5.java Constructor with Object Parameters
class Address {
    String city, state;
    
    Address(String c, String s) {
        city = c; state = s;
    }
    
    void show() {
        System.out.print(city + ", " + state);
    }
}

class Person {
    String name;
    Address addr;  // Object as field - Composition
    
    // Constructor mein Object parameter
    Person(String n, Address a) {
        name = n;
        addr = a;  // Reference copy, not deep copy!
    }
    
    void display() {
        System.out.print(name + " lives in ");
        addr.show();
        System.out.println();
    }
}

public class Constructor5 {
    public static void main(String[] args) {
        
        // Address object pehle banao
        Address home = new Address("Mumbai", "Maharashtra");
        
        // Address object ko Person constructor mein pass karo
        Person p1 = new Person("Rahul", home);
        p1.display();
        
        // ⚠️ Reference sharing - same Address object!
        Person p2 = new Person("Priya", home);
        p2.display();
        
        // home change karo β†’ dono Person affect honge!
        System.out.println("\nChanging address...");
        home.city = "Pune";
        p1.display();  // Rahul bhi Pune show karega!
        p2.display();
    }
}
β–Ά OUTPUT
Rahul lives in Mumbai, Maharashtra
Priya lives in Mumbai, Maharashtra

Changing address...
Rahul lives in Pune, Maharashtra
Priya lives in Pune, Maharashtra
πŸ’‘ Object Parameters = Reference Passing:
Constructor mein object pass karne par uska REFERENCE copy hota hai, not the object itself. Isliye original object modify karne se saare references affect hote hain. Deep copy chahiye toh constructor mein new object banao!

🟑 Topic 3: this Keyword Deep Dive

🧠 'this' Kya Hai? Memory Context:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  this = Current Object Reference β”‚
β”‚  β€’ Har non-static method ke andar β”‚
β”‚    implicitly available hota hai  β”‚
β”‚  β€’ Heap mein jo current object    β”‚
β”‚    chal raha hai, uska address    β”‚
β”‚  β€’ Static methods mein this ❌    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Use Cases:
1️⃣ Parameter vs Field name conflict resolve
2️⃣ Constructor chaining: this(...)
3️⃣ Current object return karna
4️⃣ Current object as method argument pass karna
5️⃣ Anonymous object se method call
πŸ“ ThisKeyword1.java this for Field-Parameter Conflict
class User {
    String username;
    int age;
    
    // πŸ”Ή Problem: Parameter name same as field
    User(String username, int age) {
        // username = username; ❌ Field ko assign nahi hoga!
        // Local parameter ko hi local parameter assign hoga
        
        // βœ… Solution: this se field refer karo
        this.username = username;  // LHS: field, RHS: parameter
        this.age = age;
        System.out.println("User created: " + this.username);
    }
    
    void greet() {
        // this optional hai jab conflict nahi hai
        System.out.println("Hi, I'm " + username);
        System.out.println("Age: " + this.age);  // this likh sakte hain
    }
    
    // πŸ”Ή Method chaining ke liye this return karna
    User setAge(int age) {
        this.age = age;
        return this;  // Current object return
    }
}

public class ThisKeyword1 {
    public static void main(String[] args) {
        
        User u1 = new User("coder123", 25);
        u1.greet();
        
        // Method chaining using this return
        User u2 = new User("dev456", 30);
        u2.setAge(31).greet();  // setAge returns this, then greet() call
    }
}
β–Ά OUTPUT
User created: coder123
Hi, I'm coder123
Age: 25
User created: dev456
Hi, I'm dev456
Age: 31
πŸ“ ThisKeyword2.java this for Constructor Chaining
class Mobile {
    String brand, model;
    int storage;
    double price;
    
    // Master constructor
    Mobile(String b, String m, int s, double p) {
        brand = b; model = m; storage = s; price = p;
        System.out.println("πŸ”— Master: " + brand + " " + model);
    }
    
    // this() se constructor call - MUST be first line
    Mobile(String b, String m, int s) {
        this(b, m, s, 0.0);  // βœ… First line!
        System.out.println("πŸ”— 3-param constructor");
    }
    
    Mobile(String b, String m) {
        this(b, m, 128);  // βœ… Calls 3-param β†’ which calls master
        System.out.println("πŸ”— 2-param constructor");
    }
    
    // ❌ Galat: this() first line nahi hai
    // Mobile(String b) {
    //     System.out.println("Start");
    //     this(b, "Unknown"); ❌ Compile Error!
    // }
    
    void show() {
        System.out.printf("%s %s | %dGB | β‚Ή%.2f\n", 
                         brand, model, storage, price);
    }
}

public class ThisKeyword2 {
    public static void main(String[] args) {
        
        System.out.println("=== 4-param direct ===");
        Mobile m1 = new Mobile("Apple", "iPhone15", 256, 79999);
        m1.show();
        
        System.out.println("\n=== 3-param β†’ chain ===");
        Mobile m2 = new Mobile("Samsung", "S24", 512);
        m2.show();
        
        System.out.println("\n=== 2-param β†’ chain β†’ chain ===");
        Mobile m3 = new Mobile("OnePlus", "12R");
        m3.show();
    }
}
β–Ά OUTPUT
=== 4-param direct ===
πŸ”— Master: Apple iPhone15
Apple iPhone15 | 256GB | β‚Ή79999.00

=== 3-param β†’ chain ===
πŸ”— Master: Samsung S24
πŸ”— 3-param constructor
Samsung S24 | 512GB | β‚Ή0.00

=== 2-param β†’ chain β†’ chain ===
πŸ”— Master: OnePlus 12R
πŸ”— 3-param constructor
πŸ”— 2-param constructor
OnePlus 12R | 128GB | β‚Ή0.00
πŸ’‘ this() Rules:
βœ… Constructor ke andar hi use kar sakte hain
βœ… MUST be the FIRST statement in constructor
βœ… Ek constructor mein sirf EK this() call ho sakta hai
βœ… Circular chaining (Aβ†’Bβ†’A) = Compile Error
πŸ“ ThisKeyword3.java this as Method Argument & Return
class Team {
    String name;
    
    Team(String n) { name = n; }
    
    // πŸ”Ή Current object ko as argument pass karna
    void invite(Team other) {
        System.out.println(this.name + " invites " + other.name);
    }
    
    // πŸ”Ή Current object return karna (Fluent API)
    Team getPartner(Team partner) {
        System.out.println(this.name + " + " + partner.name + " = Team Up!");
        return partner;  // ya return this; bhi kar sakte the
    }
}

class GameManager {
    // πŸ”Ή Object accept karne wala method
    static void registerTeam(Team t) {
        System.out.println("βœ… Registered: " + t.name);
    }
}

public class ThisKeyword3 {
    public static void main(String[] args) {
        
        Team t1 = new Team("Warriors");
        Team t2 = new Team("Champions");
        
        // this as argument: current object pass to another object's method
        t1.invite(t2);  // Warriors invites Champions
        t2.invite(t1);  // Champions invites Warriors
        
        // this return: method chaining
        System.out.println();
        t1.getPartner(t2).invite(t1);  // getPartner returns t2, then t2.invite(t1)
        
        // Passing current object to static method
        System.out.println();
        GameManager.registerTeam(t1);  // Explicit
        GameManager.registerTeam(this);  // ❌ Error! static context mein this nahi
    }
}
β–Ά OUTPUT
Warriors invites Champions
Champions invites Warriors

Warriors + Champions = Team Up!
Champions invites Warriors

βœ… Registered: Warriors
// Error: non-static variable this cannot be referenced from a static context
πŸ’‘ this in Static Context:
❌ Static methods/variables class-level hote hain, object-level nahi
❌ Isliye static method ke andar this use nahi kar sakte
βœ… Static method mein object reference pass karo agar instance access karna ho
πŸ“ ThisKeyword4.java this with Anonymous Objects
class Calculator {
    int result = 0;
    
    Calculator add(int x) { 
        result += x; 
        return this;  // Fluent chaining
    }
    
    int getResult() { return result; }
    
    // πŸ”Ή Current object ko compare karna
    boolean isSame(Calculator other) {
        return this == other;  // Reference comparison
    }
}

public class ThisKeyword4 {
    public static void main(String[] args) {
        
        // πŸ”Ή Anonymous object - reference variable nahi, direct use
        int val = new Calculator().add(10).add(20).getResult();
        System.out.println("Anonymous chain result: " + val);
        
        // πŸ”Ή Anonymous object as method argument
        Calculator calc1 = new Calculator();
        calc1.add(5);
        
        // Anonymous object pass to method
        boolean same = calc1.isSame(new Calculator());  // false - different objects
        System.out.println("Same object? " + same);
        
        // πŸ”Ή this return se chaining
        Calculator calc2 = new Calculator();
        calc2.add(1).add(2).add(3);  // add() returns this
        System.out.println("Chained result: " + calc2.getResult());
        
        // πŸ”Ή Anonymous with immediate method call
        System.out.println("One-liner: " + new Calculator().add(100).getResult());
    }
}
β–Ά OUTPUT
Anonymous chain result: 30
Same object? false
Chained result: 6
One-liner: 100
πŸ’‘ Anonymous Objects:
βœ… new ClassName() bina reference variable ke = Anonymous object
βœ… Turant method call kar sakte hain: new Calc().add(5)
βœ… Object ek baar use hoga, fir GC eligible (agar koi reference nahi)
βœ… Fluent APIs aur builder pattern mein bahut useful
πŸ“ ThisKeyword5.java this vs super in Inheritance
class Parent {
    String name = "Parent";
    
    void show() {
        System.out.println("Parent show: " + name);
    }
}

class Child extends Parent {
    String name = "Child";  // Field hiding
    
    void show() {  // Method overriding
        System.out.println("Child show: " + name);           // Child's name
        System.out.println("this.name: " + this.name);       // Child's name
        System.out.println("super.name: " + super.name);     // Parent's name
        
        this.show();    // Child's show (recursive! careful)
        // super.show();  // Parent's show call kar sakte the
    }
    
    Child() {
        // super(); implicitly called first by compiler
        System.out.println("Child constructor");
    }
    
    Child(String n) {
        super();  // βœ… Explicit super() call - must be first
        this.name = n;  // this se current class field
    }
}

public class ThisKeyword5 {
    public static void main(String[] args) {
        
        Child c = new Child("Little");
        
        System.out.println("\n=== Accessing fields ===");
        System.out.println("c.name: " + c.name);           // Child's (hiding)
        System.out.println("((Parent)c).name: " + ((Parent)c).name);  // Parent's via casting
        
        System.out.println("\n=== Calling methods ===");
        c.show();  // Overridden method - Child's version
        // ((Parent)c).show();  // Parent's version call kar sakte the
    }
}
β–Ά OUTPUT
Child constructor

=== Accessing fields ===
c.name: Little
((Parent)c).name: Parent

=== Calling methods ===
Child show: Little
this.name: Little
super.name: Parent
Child show: Little
this.name: Little
super.name: Parent
Child show: Little
... // ⚠️ Infinite recursion! this.show() calls itself
πŸ’‘ this vs super Summary:
πŸ”Ή this.field β†’ Current class ka field (hiding case mein)
πŸ”Ή super.field β†’ Parent class ka field
πŸ”Ή this.method() β†’ Current class ka method (overriding case)
πŸ”Ή super.method() β†’ Parent class ka overridden method
πŸ”Ή this(...) β†’ Same class ka constructor
πŸ”Ή super(...) β†’ Parent class ka constructor
⚠️ this.show() inside show() = infinite recursion! Use super.show() to call parent version

🟣 Topic 4: Methods & Overloading Deep Dive

🧠 Method Memory Model:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Method Types:               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ πŸ”Ή Instance Method          β”‚
β”‚    β€’ Object ke through call β”‚
β”‚    β€’ this available         β”‚
β”‚    β€’ Instance vars access   β”‚
β”‚                             β”‚
β”‚ πŸ”Ή Static Method            β”‚
β”‚    β€’ Class ke through call  β”‚
β”‚    β€’ this ❌ not available  β”‚
β”‚    β€’ Only static vars       β”‚
β”‚                             β”‚
β”‚ πŸ”Ή Varargs Method           β”‚
β”‚    β€’ Variable arguments     β”‚
β”‚    β€’ type... paramName      β”‚
β”‚    β€’ Internally array       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Method Overloading = Same name, DIFFERENT parameters
β€’ Compile-time polymorphism
β€’ Return type alone se overload nahi hota!
β€’ Compiler: argument count + type + order dekhta hai
πŸ“ Method1.java Instance vs Static Methods
class Counter {
    // Instance variable - har object ka alag
    int instanceCount = 0;
    
    // Static variable - sab objects share karte hain
    static int staticCount = 0;
    
    // πŸ”Ή Instance Method
    void incrementInstance() {
        instanceCount++;
        staticCount++;  // Instance method static bhi access kar sakta
        System.out.println("Instance: " + instanceCount + ", Static: " + staticCount);
    }
    
    // πŸ”Ή Static Method
    static void incrementStatic() {
        staticCount++;
        // instanceCount++; ❌ Error! Static can't access instance directly
        System.out.println("Static only: " + staticCount);
    }
    
    // πŸ”Ή Static method mein instance access kaise karein?
    static void accessViaObject(Counter c) {
        c.instanceCount++;  // βœ… Object reference se access kar sakte
        System.out.println("Via object: " + c.instanceCount);
    }
}

public class Method1 {
    public static void main(String[] args) {
        
        // Static method call - class name se
        Counter.incrementStatic();  // βœ… Preferred
        // new Counter().incrementStatic();  // βœ… Works but not preferred
        
        // Instance method call - object se hi
        Counter c1 = new Counter();
        c1.incrementInstance();  // βœ… instanceCount=1, staticCount=1
        
        Counter c2 = new Counter();
        c2.incrementInstance();  // βœ… instanceCount=1 (new object), staticCount=2
        
        System.out.println("\nc1.instanceCount: " + c1.instanceCount);  // 1
        System.out.println("c2.instanceCount: " + c2.instanceCount);  // 1
        System.out.println("Counter.staticCount: " + Counter.staticCount);  // 2
        
        // Static method se instance access via object
        Counter.accessViaObject(c1);  // c1.instanceCount becomes 2
        System.out.println("After static call: c1.instanceCount = " + c1.instanceCount);
    }
}
β–Ά OUTPUT
Static only: 1
Instance: 1, Static: 2
Instance: 1, Static: 3

c1.instanceCount: 1
c2.instanceCount: 1
Counter.staticCount: 3
Via object: 2
After static call: c1.instanceCount = 2
πŸ’‘ Instance vs Static Golden Rules:
βœ… Instance method β†’ Instance + Static dono access kar sakta
❌ Static method β†’ Sirf Static access kar sakta (instance directly nahi)
βœ… Static method mein instance access karna ho toh object reference pass karo
βœ… Static variable/method ko class name se call karo: ClassName.method()
πŸ“ Method2.java Method Overloading - Compile Time Polymorphism
class Printer {
    
    // πŸ”Ή Overload 1: No param
    void print() {
        System.out.println("[No Data]");
    }
    
    // πŸ”Ή Overload 2: int param
    void print(int n) {
        System.out.println("Integer: " + n);
    }
    
    // πŸ”Ή Overload 3: double param (different type)
    void print(double d) {
        System.out.println("Double: " + d);
    }
    
    // πŸ”Ή Overload 4: String param
    void print(String s) {
        System.out.println("String: " + s);
    }
    
    // πŸ”Ή Overload 5: int + String (different count + type)
    void print(int n, String s) {
        System.out.println("Int+String: " + n + " - " + s);
    }
    
    // πŸ”Ή Overload 6: String + int (order matters!)
    void print(String s, int n) {
        System.out.println("String+Int: " + s + " - " + n);
    }
    
    // ❌ Ye overload nahi hai - sirf return type different!
    // String print(int n) { return ""+n; } ❌ Compile Error!
}

public class Method2 {
    public static void main(String[] args) {
        
        Printer p = new Printer();
        
        // Compiler decide karega kaunsa method call karna hai
        // Based on: argument count + type + order
        
        p.print();                    // Calls print()
        p.print(42);                  // Calls print(int)
        p.print(3.14);                // Calls print(double)
        p.print("Hello");             // Calls print(String)
        p.print(100, "Score");        // Calls print(int, String)
        p.print("Rank", 1);           // Calls print(String, int)
        
        // πŸ”Ή Type Promotion in Overloading
        byte b = 10;
        p.print(b);  // byte β†’ int promotion β†’ print(int) call hoga
        
        // πŸ”Ή Ambiguity - Compiler confuse!
        // p.print(null); ❌ Compile Error! print(String) or print(int[])?
    }
}
β–Ά OUTPUT
[No Data]
Integer: 42
Double: 3.14
String: Hello
Int+String: 100 - Score
String+Int: Rank - 1
Integer: 10
πŸ’‘ Overloading Rules:
βœ… Same method name, DIFFERENT parameter list
βœ… Parameter: count OR type OR order - koi bhi different ho
❌ Sirf return type different = NOT overloading = Compile Error
βœ… Type promotion: byteβ†’shortβ†’intβ†’longβ†’floatβ†’double (auto)
⚠️ print(null) ambiguous ho sakta hai agar multiple reference types hain
πŸ“ Method3.java Varargs - Variable Arguments
class MathUtils {
    
    // πŸ”Ή Varargs method: type... name = array internally
    static int sum(int... numbers) {
        // numbers is actually int[] array
        int total = 0;
        for (int n : numbers) {
            total += n;
        }
        return total;
    }
    
    // πŸ”Ή Varargs with other parameters - varargs MUST be last
    static String join(String separator, String... words) {
        if (words.length == 0) return "";
        
        StringBuilder sb = new StringBuilder(words[0]);
        for (int i = 1; i < words.length; i++) {
            sb.append(separator).append(words[i]);
        }
        return sb.toString();
    }
    
    // ❌ Galat: varargs last mein nahi hai
    // static void wrong(int... nums, String s) {} ❌ Compile Error!
    
    // πŸ”Ή Overloading with varargs
    static void display(String msg) {
        System.out.println("Single: " + msg);
    }
    
    static void display(String... msgs) {
        System.out.print("Varargs: ");
        for(String m : msgs) System.out.print(m + " ");
        System.out.println();
    }
}

public class Method3 {
    public static void main(String[] args) {
        
        // πŸ”Ή Varargs: 0, 1, or multiple arguments
        System.out.println("Sum of []: " + MathUtils.sum());              // 0 args
        System.out.println("Sum of [5]: " + MathUtils.sum(5));            // 1 arg
        System.out.println("Sum of [1,2,3]: " + MathUtils.sum(1,2,3));    // multiple
        
        // πŸ”Ή Array bhi pass kar sakte hain varargs mein
        int[] arr = {10, 20, 30};
        System.out.println("Sum of array: " + MathUtils.sum(arr));
        
        // πŸ”Ή Varargs with other params
        System.out.println("\nJoin: " + MathUtils.join("-", "Java", "is", "awesome"));
        System.out.println("Join (1 word): " + MathUtils.join(",", "Solo"));
        
        // πŸ”Ή Overloading: String vs String... - which one calls?
        MathUtils.display("Hello");  // Calls display(String) - more specific!
        MathUtils.display("A", "B");  // Calls display(String...) - only option
    }
}
β–Ά OUTPUT
Sum of []: 0
Sum of [5]: 5
Sum of [1,2,3]: 6
Sum of array: 60

Join: Java-is-awesome
Join (1 word): Solo

Single: Hello
Varargs: A B
πŸ’‘ Varargs Rules:
βœ… Syntax: type... paramName (three dots)
βœ… Internally array hota hai - for-each se iterate kar sakte
βœ… Varargs parameter MUST be the LAST parameter
βœ… Ek method mein sirf EK varargs parameter ho sakta hai
βœ… 0, 1, or multiple arguments pass kar sakte
βœ… Array bhi directly pass kar sakte: method(arr)
βœ… Overloading mein: exact match > varargs (more specific wins)
πŸ“ Method4.java Pass-by-Value Deep Dive with Objects
class Box {
    int value;
    Box(int v) { value = v; }
}

public class Method4 {
    
    // πŸ”Ή Primitive: Pass by Value - copy of value
    static void modifyPrimitive(int x) {
        x = 999;
        System.out.println("Inside primitive: " + x);
    }
    
    // πŸ”Ή Object Reference: Pass by Value OF Reference
    // Reference ki copy pass hoti hai, not the reference itself
    static void modifyObjectField(Box b) {
        b.value = 999;  // βœ… Original object modify - same heap location
        System.out.println("Inside object field: " + b.value);
    }
    
    // πŸ”Ή Reassigning the reference parameter
    static void reassignReference(Box b) {
        b = new Box(777);  // βœ… New object, local reference change only
        System.out.println("Inside reassign: " + b.value);
        // Original reference unaffected!
    }
    
    // πŸ”Ή Swapping objects - doesn't work like you think!
    static void trySwap(Box a, Box b) {
        Box temp = a;
        a = b;
        b = temp;
        System.out.println("Inside swap: a=" + a.value + ", b=" + b.value);
        // Original references unchanged!
    }
    
    public static void main(String[] args) {
        
        // Primitive test
        int num = 10;
        System.out.println("Before primitive: " + num);
        modifyPrimitive(num);
        System.out.println("After primitive: " + num + " (unchanged)\n");
        
        // Object field modify test
        Box box1 = new Box(10);
        System.out.println("Before object field: " + box1.value);
        modifyObjectField(box1);
        System.out.println("After object field: " + box1.value + " (CHANGED!)\n");
        
        // Reference reassign test
        Box box2 = new Box(10);
        System.out.println("Before reassign: " + box2.value);
        reassignReference(box2);
        System.out.println("After reassign: " + box2.value + " (unchanged!)\n");
        
        // Swap attempt
        Box x = new Box(100), y = new Box(200);
        System.out.println("Before swap: x=" + x.value + ", y=" + y.value);
        trySwap(x, y);
        System.out.println("After swap: x=" + x.value + ", y=" + y.value + " (unchanged!)");
    }
}
β–Ά OUTPUT
Before primitive: 10
Inside primitive: 999
After primitive: 10 (unchanged)

Before object field: 10
Inside object field: 999
After object field: 999 (CHANGED!)

Before reassign: 10
Inside reassign: 777
After reassign: 10 (unchanged!)

Before swap: x=100, y=200
Inside swap: a=200, b=100
After swap: x=100, y=200 (unchanged!)
πŸ’‘ Java is ALWAYS Pass-by-Value!
πŸ”Ή Primitive: Value ki copy pass hoti hai β†’ original unchanged
πŸ”Ή Object: Reference ki VALUE copy hoti hai β†’ same heap object, so field modify affects original
πŸ”Ή Reference reassign in method β†’ local copy change, original unchanged
πŸ”Ή Isliye "swap" method se do objects swap nahi hote! Return karke ya array use karo
πŸ“ Method5.java Method Returning Objects & Chaining
class Builder {
    StringBuilder sb = new StringBuilder();
    
    // πŸ”Ή Fluent API: Return this for chaining
    Builder append(String s) {
        sb.append(s);
        return this;  // Return current object
    }
    
    Builder append(int n) {
        sb.append(n);
        return this;
    }
    
    // πŸ”Ή Return new object (Factory pattern)
    static Builder create() {
        return new Builder();
    }
    
    // πŸ”Ή Return different type
    String build() {
        return sb.toString();
    }
    
    // πŸ”Ή Return object based on condition
    static Builder fromTemplate(String template) {
        Builder b = new Builder();
        if (template.equals("greet")) {
            b.sb.append("Hello, ");
        } else if (template.equals("farewell")) {
            b.sb.append("Goodbye, ");
        }
        return b;
    }
}

public class Method5 {
    public static void main(String[] args) {
        
        // πŸ”Ή Fluent chaining with returned 'this'
        String result1 = Builder.create()
            .append("Java ")
            .append("is ")
            .append("awesome")
            .append("!")
            .build();
        System.out.println(result1);
        
        // πŸ”Ή Factory method returning object
        String greet = Builder.fromTemplate("greet")
            .append("World")
            .build();
        System.out.println(greet);
        
        String bye = Builder.fromTemplate("farewell")
            .append("Java")
            .build();
        System.out.println(bye);
        
        // πŸ”Ή Method returning object stored in variable
        Builder b = Builder.create();
        b.append("Stored ").append(123);
        System.out.println(b.build());
    }
}
β–Ά OUTPUT
Java is awesome!
Hello, World
Goodbye, Java
Stored 123
πŸ’‘ Method Return Patterns:
βœ… Return this β†’ Fluent API / Method chaining
βœ… Return new object β†’ Factory pattern, immutability
βœ… Return based on condition β†’ Strategy/Template pattern
βœ… Builder pattern: Collect data β†’ build() β†’ return final object
⚠️ Returning this se external code bhi object modify kar sakta hai - encapsulation break ho sakta hai

πŸ”΅ Topic 5: Access Modifiers Quick Guide

🧠 Access Control Matrix:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Modifier   β”‚ Class   β”‚ Package β”‚ Subclassβ”‚ World   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ private    β”‚ βœ…      β”‚ ❌      β”‚ ❌      β”‚ ❌      β”‚
β”‚ (default)  β”‚ βœ…      β”‚ βœ…      β”‚ ❌*     β”‚ ❌      β”‚
β”‚ protected  β”‚ βœ…      β”‚ βœ…      β”‚ βœ…      β”‚ ❌      β”‚
β”‚ public     β”‚ βœ…      β”‚ βœ…      β”‚ βœ…      β”‚ βœ…      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
*default: subclass in SAME package only
πŸ“ Access1.java private - Class Level Only
class BankAccount {
    private double balance;  // πŸ”’ Outside class se direct access nahi
    
    public BankAccount(double initial) {
        balance = initial;
    }
    
    // πŸ”“ Controlled access via public methods
    public void deposit(double amount) {
        if (amount > 0) balance += amount;
    }
    
    public double getBalance() {
        return balance;  // Read-only access
    }
    
    // πŸ”Ή Private method - only usable inside this class
    private boolean isValid(double amount) {
        return amount > 0 && amount <= 100000;
    }
}

public class Access1 {
    public static void main(String[] args) {
        BankAccount acc = new BankAccount(1000);
        
        acc.deposit(500);  // βœ… Public method
        System.out.println("Balance: β‚Ή" + acc.getBalance());  // βœ…
        
        // acc.balance = 999999; ❌ Compile Error: private
        // acc.isValid(100); ❌ Compile Error: private method
    }
}
β–Ά OUTPUT
Balance: β‚Ή1500.0
πŸ’‘ Encapsulation Principle:
βœ… Fields ko private rakho
βœ… Access ke liye public getter/setters do
βœ… Validation logic setter mein daalo
βœ… Internal helper methods ko private rakho
πŸ“ Access2.java protected - Inheritance Access
// File: pkg1/Parent.java
package pkg1;

public class Parent {
    protected int protectedValue = 100;
    
    protected void show() {
        System.out.println("Protected: " + protectedValue);
    }
}

// File: pkg1/Child.java (same package)
package pkg1;

public class Child extends Parent {
    public void access() {
        protectedValue = 200;  // βœ… Same package + subclass
        show();  // βœ…
    }
}

// File: pkg2/Other.java (different package, not subclass)
package pkg2;
import pkg1.Parent;

public class Other {
    public static void main(String[] args) {
        Parent p = new Parent();
        // p.protectedValue = 50; ❌ Error: not subclass + different package
        // p.show(); ❌ Error
    }
}

// File: pkg2/Sub.java (different package, IS subclass)
package pkg2;
import pkg1.Parent;

public class Sub extends Parent {
    public void test() {
        // protectedValue = 300; ❌ Can access ONLY via inheritance
        super.protectedValue = 300;  // βœ… Via super/this
        super.show();  // βœ…
        
        Parent p = new Parent();
        // p.protectedValue = 400; ❌ Can't access via different package reference
    }
}
πŸ’‘ protected Key Points:
βœ… Same package: Sab classes access kar sakti hain (like default)
βœ… Different package + subclass: Sirf inheritance ke through access
❌ Different package + NOT subclass: No access
βœ… Best for: Framework design, template method pattern

πŸ“‹ Complete Revision Summary

ConceptKey Points
ClassBlueprint | No memory | Contains fields + methods | Template for objects
ObjectInstance of class | Heap memory | Created with new | Has state + behavior
ConstructorSame name as class | No return type | Auto-called with new | Overloading possible
thisCurrent object reference | Field conflict resolve | Constructor chaining | Method chaining
Instance MethodObject se call | Access instance+static | this available
Static MethodClass se call | Only static access | this ❌ | Utility methods
OverloadingSame name, diff params | Compile-time polymorphism | Return type alone β‰  overload
Access Modifiersprivate < default < protected < public | Encapsulation ke liye use
Encapsulationprivate fields + public getters/setters | Data hiding + validation
Pass-by-ValueJava ALWAYS pass-by-value | Object: reference ki value copy | Field modify = original affect
πŸ† GOLDEN RULES FOR BACKEND DEVELOPMENT

βœ… Best Practices Checklist:

1️⃣ Class Design:
   β€’ Single Responsibility Principle - Ek class = Ek kaam
   β€’ Meaningful class/method names - Self-documenting code
   β€’ Keep classes small and focused

2️⃣ Encapsulation:
   β€’ Fields β†’ private
   β€’ Access β†’ public getters/setters with validation
   β€’ Expose minimum API surface

3️⃣ Constructors:
   β€’ Use constructor chaining for code reuse
   β€’ Validate parameters in constructor
   β€’ Consider Builder pattern for complex objects

4️⃣ Methods:
   β€’ Keep methods small (single responsibility)
   β€’ Use meaningful parameter names
   β€’ Prefer immutable objects where possible
   β€’ Document with JavaDoc

5️⃣ Memory Management:
   β€’ Null references explicitly when done
   β€’ Avoid memory leaks in collections
   β€’ Use try-with-resources for AutoCloseable

6️⃣ Thread Safety (Backend Critical):
   β€’ Immutable objects are thread-safe by default
   β€’ Synchronize shared mutable state
   β€’ Prefer concurrent collections

7️⃣ Testing:
   β€’ Design classes to be testable (dependency injection)
   β€’ Avoid static state in business logic
   β€’ Use interfaces for mocking
⚠️ Common Mistakes to Avoid:
❌ Public fields β†’ Breaks encapsulation, hard to maintain
❌ Large constructors with many params β†’ Use Builder pattern
❌ Returning mutable internal collections β†’ Return unmodifiable view
❌ Ignoring null checks β†’ Use Optional or validate early
❌ Overusing static β†’ Hard to test, breaks OOP principles
❌ Circular dependencies between classes β†’ Refactor with interfaces
πŸ“ FinalExample.java Putting It All Together - Backend Entity
// πŸ”Ή Well-designed backend entity class
public final class User {  // final = immutable, thread-safe
    
    // πŸ”’ Private final fields - immutable after construction
    private final String userId;
    private final String email;
    private final String passwordHash;  // Never store plain password!
    private final UserRole role;
    
    // πŸ”Ή Private constructor - force use of Builder
    private User(Builder builder) {
        this.userId = validateNotEmpty(builder.userId, "userId");
        this.email = validateEmail(builder.email);
        this.passwordHash = builder.passwordHash;  // Already hashed
        this.role = builder.role != null ? builder.role : UserRole.USER;
    }
    
    // πŸ”Ή Public getters - NO setters (immutable)
    public String getUserId() { return userId; }
    public String getEmail() { return email; }
    public UserRole getRole() { return role; }
    
    // πŸ”Ή Business logic methods
    public boolean hasRole(UserRole required) {
        return this.role.getLevel() >= required.getLevel();
    }
    
    public boolean verifyPassword(String plainPassword, PasswordEncoder encoder) {
        return encoder.matches(plainPassword, this.passwordHash);
    }
    
    // πŸ”Ή Helper validation methods (private)
    private static String validateNotEmpty(String value, String fieldName) {
        if (value == null || value.isBlank()) {
            throw new IllegalArgumentException(fieldName + " cannot be empty");
        }
        return value;
    }
    
    private static String validateEmail(String email) {
        // Simple email validation - use library in production
        if (!email.matches(".+@.+\\..+")) {
            throw new IllegalArgumentException("Invalid email");
        }
        return email.toLowerCase();  // Normalize
    }
    
    // πŸ”Ή Builder Pattern for flexible object creation
    public static class Builder {
        private String userId, email, passwordHash;
        private UserRole role;
        
        public Builder userId(String id) { this.userId = id; return this; }
        public Builder email(String email) { this.email = email; return this; }
        public Builder passwordHash(String hash) { this.passwordHash = hash; return this; }
        public Builder role(UserRole role) { this.role = role; return this; }
        
        public User build() {
            return new User(this);  // Private constructor access
        }
    }
    
    // πŸ”Ή Override Object methods for proper behavior
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;
        User user = (User) o;
        return userId.equals(user.userId);  // Business key
    }
    
    @Override
    public int hashCode() {
        return userId.hashCode();
    }
    
    @Override
    public String toString() {
        return "User{userId='" + userId + "', email='" + email + "', role=" + role + '}';
    }
}

// πŸ”Ή Usage Example
public class FinalExample {
    public static void main(String[] args) {
        
        // βœ… Builder pattern - readable, flexible, validated
        User admin = new User.Builder()
            .userId("admin001")
            .email("admin@company.com")
            .passwordHash("$2a$10$...hashed...")
            .role(UserRole.ADMIN)
            .build();
        
        System.out.println(admin);
        System.out.println("Is admin? " + admin.hasRole(UserRole.ADMIN));
        
        // ❌ This won't compile - immutable!
        // admin.email = "hacked@evil.com"; // Compile Error
    }
}

enum UserRole {
    USER(1), MODERATOR(2), ADMIN(3);
    private final int level;
    UserRole(int l) { level = l; }
    public int getLevel() { return level; }
}
🎯 Backend Development Takeaways:
βœ… Immutable entities = Thread-safe + Predictable
βœ… Builder pattern = Clean object creation with validation
βœ… Encapsulation = Control data access + Add business logic
βœ… Override equals/hashCode = Proper collection behavior
βœ… Validate early = Fail fast, clear error messages
βœ… Use enums for fixed sets = Type safety + IDE support
πŸ† File Name = Public Class Name Exactly!
Jaise: public class User β†’ File: User.java