14. జావా OOP మూలాలు — క్లాసులు, ఆబ్జెక్టులు & హీప్ మెమరీ (Classes, Objects & Heap)

☕ Java (Java 21+ LTS) 🟢 Lesson 14 of 25 📂 Part 03: Arrays, Methods & OOP (Page 4 of 5) ⏱️ 26 min read
📌 Covered in this lesson: ఆబ్జెక్ట్ ఓరియెంటెడ్ పారాడైమ్ · State & Behavior · new కీవర్డ్ ద్వారా Heap మెమరీ అలోకేషన్ · Instance vs Static వేరియబుల్స్ · Garbage Collection బేసిక్స్

సాఫ్ట్‌వేర్ ఇంజనీరింగ్ రంగంలో నిత్యజీవితంలోని వాస్తవిక భావనలను (Real-world Entities) కంప్యూటర్ ప్రోగ్రామ్‌లుగా మలచడానికి ఉద్భవించిన అత్యంత విప్లవాత్మకమైన ప్రోగ్రామింగ్ పద్ధతి ఆబ్జెక్ట్-ఓరియెంటెడ్ ప్రోగ్రామింగ్ (Object-Oriented Programming - OOP). జావాలో సమస్తమూ క్లాసులు మరియు ఆబ్జెక్టుల చుట్టూనే పరిభ్రమిస్తుంది. ఒక క్లాస్ అనేది కేవలం ఒక బ్లూప్రింట్ లేదా ప్లాన్ మాత్రమే కాగా, ఆ ప్లాన్ ఆధారంగా new కీవర్డ్ ద్వారా JVM హీప్ మెమరీలో ప్రాణం పోసుకునే సజీవ అస్తిత్వమే ఆబ్జెక్ట్ (Object / Instance). ఆబ్జెక్ట్ యొక్క స్థితి (State) మరియు ప్రవర్తన (Behavior) అంటే ఏమిటి? ఒకే క్లాస్ నుండి పుట్టిన బహుళ ఆబ్జెక్టులు హీప్ మెమరీలో ఎలా కేటాయించబడతాయి? ఇన్‌స్టాన్స్ వేరియబుల్స్ మరియు స్టాటిక్ క్లాస్ వేరియబుల్స్ మధ్య మెమరీ విభజన ఎలా జరుగుతుంది? ఆబ్జెక్ట్ హెడర్లలో ఉండే Mark Word మరియు Klass Word ల పాత్ర ఏమిటి? రిఫరెన్స్ తెగిపోయిన అనాథ ఆబ్జెక్టులను గార్బేజ్ కలెక్టర్ (GC) ఎలా క్లీన్ చేస్తుంది? అనే ప్రాథమిక మరియు లోతైన OOP ఆర్కిటెక్చరల్ పునాదులను ఈ పాఠంలో సమగ్రంగా నేర్చుకుందాం.

ఆర్కిటెక్ట్ హౌస్ బ్లూప్రింట్ & వాస్తవ విల్లా భవనాల అనాలజీ (The Architect Blueprint & Real Villa Analogy):

  1. 1. Class (ఆర్కిటెక్ట్ కాగితంపై గీసిన విల్లా ప్లాన్ - Blueprint): ఒక ఆర్కిటెక్ట్ ఒక కాగితంపై లగ్జరీ 3-BHK విల్లా ప్లాన్ గీశాడు. ఆ ప్లాన్‌లో బెడ్‌రూమ్‌లు ఎక్కడ ఉండాలి, హాల్ ఎక్కడ ఉండాలి, తలుపులు ఎలా ఉండాలి అని రాసి ఉంటుంది. కానీ కాగితంపై ఉన్న ప్లాన్‌లో ఎవరూ నివసించలేరు; ఆ ప్లాన్‌కు భూమిపై ఎటువంటి భౌతిక స్థలం (RAM/Memory) అవసరం లేదు. జావాలో క్లాస్ అనేది కూడా కేవలం ఒక డాటా టైప్ బ్లూప్రింట్ మాత్రమే.
  2. 2. Object (ఆ ప్లాన్‌తో భూమిపై నిర్మించిన వాస్తవ భవనం - Real Brick-and-Mortar House): ఆ ఒక్క బ్లూప్రింట్‌ను ఉపయోగించి భూమిపై 10 విల్లాలు నిర్మించవచ్చు. Villa 1 లో బాలాజీ నివసిస్తూ నీలం రంగు వేసుకోవచ్చు, Villa 2 లో కార్తీక్ నివసిస్తూ పసుపు రంగు వేసుకోవచ్చు. ప్రతి ఇంటికీ భూమిపై సొంత స్థలం (హీప్ మెమరీ), సొంత తలుపులు, సొంత ఫర్నిచర్ (State) ఉంటాయి. ప్లాన్ ఒక్కటే అయినప్పటికీ ప్రతి ఇల్లా ఒక స్వతంత్రమైన ఆబ్జెక్ట్!
  3. 3. Static vs Instance (కాలనీ సెంట్రల్ వాటర్ ట్యాంక్ vs బెడ్‌రూమ్ ట్యాప్ - Central Water Tank vs Room Tap): ప్రతి ఇంట్లోని కిచెన్‌లో ఉండే వాష్ బేసిన్ ఆ ఇంటికి మాత్రమే ప్రత్యేకం (Instance Variable). కానీ గేటెడ్ కమ్యూనిటీ మొత్తం కోసం రోడ్డుపై ఏర్పాటు చేసిన సెంట్రల్ ఓవర్‌హెడ్ వాటర్ ట్యాంక్ లేదా సెక్యూరిటీ గేటు అందరికీ ఉమ్మడి (Static Variable). ఒక ఇంట్లో ట్యాప్ విరిగితే మిగతా ఇళ్లకు ఎటువంటి ఇబ్బంది ఉండదు, కానీ సెంట్రల్ వాటర్ ట్యాంక్‌లో నీళ్లు ఆగిపోతే మొత్తం కాలనీలోని ఇళ్లన్నీ ప్రభావితమవుతాయి!

ఈ పాఠం పూర్తయ్యేసరికి మీరు ఆబ్జెక్టుల మెమరీ లేఅవుట్‌ను సంపూర్ణంగా ఊహించగలగడం, ఇన్‌స్టాన్స్ vs స్టాటిక్ ఆర్కిటెక్చరల్ నిర్ణయాలను నిక్కచ్చిగా తీసుకోవడం, మరియు ప్రొడక్షన్-గ్రేడ్ బ్యాంకింగ్ డొమైన్ కోర్ ఇంజిన్‌ను రూపొందించడంలో నిపుణులవుతారు!

📑 ఈ పాఠంలో మీరు నేర్చుకునే అంశాలు (Table of Contents)
విభాగం A: OOP మూలాలు & ఆబ్జెక్ట్ మెమరీ
విభాగం B: వేరియబుల్స్ & గార్బేజ్ కలెక్షన్
విభాగం C: డెమోలు, ప్రాజెక్ట్ & పరీక్ష

1. ఆబ్జెక్ట్ ఓరియెంటెడ్ పారాడైమ్ & 4 ప్రధాన స్తంభాలు (The OOP Paradigm)

గతంలో C లాంటి ప్రొసీజరల్ భాషలలో ప్రోగ్రామ్ అంటే కేవలం కొన్ని ఫంక్షన్లు మరియు గ్లోబల్ డేటా సమాహారంగా ఉండేది. డేటాకు ఎటువంటి భద్రత ఉండేది కాదు; ఏ ఫంక్షన్ అయినా ఏ డేటానైనా మార్చివేయగలదు. సాఫ్ట్‌వేర్ పరిమాణం పెరిగేకొద్దీ ఇది తీవ్రమైన సంక్షోభాలకు దారితీసింది.

ఈ సమస్యకు పరిష్కారంగా ఆబ్జెక్ట్-ఓరియెంటెడ్ ప్రోగ్రామింగ్ (OOP) ఆవిర్భవించింది. OOP లో డేటా (State) మరియు ఆ డేటాపై పనిచేసే ఫంక్షన్లు (Behavior) రెండింటినీ కలిపి ఒకే గొడుగు క్రిందకు తీసుకొస్తారు. దీనినే ఆబ్జెక్ట్ (Object) అంటారు.

జావా OOP యొక్క 4 ప్రధాన స్తంభాలు (The 4 Pillars):

  • 1. ఎన్‌క్యాప్సులేషన్ (Encapsulation): డేటాను ప్రైవేట్‌గా దాచిపెట్టి, కేవలం సురక్షితమైన పబ్లిక్ మెథడ్స్ ద్వారా మాత్రమే యాక్సెస్ కల్పించడం (Data Hiding).
  • 2. వారసత్వం (Inheritance): ఇప్పటికే ఉన్న క్లాస్ నుండి కొత్త క్లాస్‌ను రూపొందిస్తూ కోడ్ పునర్వినియోగాన్ని (Code Reusability) సాధించడం.
  • 3. పాలిమార్ఫిజం (Polymorphism): ఒకే మెథడ్ లేదా ఆపరేషన్ వేర్వేరు రూపాల్లో ప్రవర్తించే సామర్థ్యం (One Interface, Multiple Implementations).
  • 4. ఆబ్‌స్ట్రాక్షన్ (Abstraction): అంతర్గత సంక్లిష్టమైన ఇంప్లిమెంటేషన్‌ను దాచిపెట్టి, వినియోగదారుకు కేవలం అవసరమైన ఫీచర్లను మాత్రమే చూపించడం.

2. క్లాస్ (బ్లూప్రింట్) vs ఆబ్జెక్ట్ (ఇన్‌స్టాన్స్) (Class vs Object)

ఈ రెండింటి మధ్య తేడాను స్పష్టంగా అర్థం చేసుకోవడం చాలా సులభం:

// 1. క్లాస్ డిక్లరేషన్: ఇది బ్లూప్రింట్ మాత్రమే (మెమరీ తీసుకోదు)
public class Car {
    String model;  // State (Field)
    int speed;     // State (Field)

    void accelerate() {  // Behavior (Method)
        speed += 10;
    }
}

// 2. ఆబ్జెక్ట్ క్రియేషన్: హీప్ మెమరీలో వాస్తవ ఇన్‌స్టాన్స్ పుడుతుంది
Car myCar = new Car();
myCar.model = "Tesla Model 3";
myCar.accelerate();

ప్రతి ఆబ్జెక్ట్‌కు రెండు ప్రాథమిక లక్షణాలు ఉంటాయి:
• State (స్థితి): ఆబ్జెక్ట్ లోపల నిల్వ చేయబడిన ఫీల్డ్స్ లేదా వేరియబుల్స్ విలువలు.
• Behavior (ప్రవర్తన): ఆబ్జెక్ట్ చేసే పనులు లేదా మెథడ్స్.

3. new కీవర్డ్ & JVM హీప్ అలొకేషన్ 4 స్టెప్స్ (The 4 Steps of Object Creation)

మీరు జావాలో Car c = new Car(); అని రాసినప్పుడు తెరవెనుక JVM లో సరిగ్గా ఏమి జరుగుతుంది? JVM ఈ ప్రక్రియను 4 నిక్కచ్చితమైన దశల్లో పూర్తి చేస్తుంది:

  1. దశ 1 (Class Loading & Verification): Car క్లాస్ బైట్‌కోడ్ ముందే మెమరీలో లేకపోతే, ClassLoader దాన్ని Metaspace లోకి లోడ్ చేసి వెరిఫై చేస్తుంది.
  2. దశ 2 (Heap Memory Allocation): హీప్ మెమరీలోని Young Generation (Eden Space) లో ఆబ్జెక్ట్ యొక్క ఫీల్డ్స్ మరియు ఆబ్జెక్ట్ హెడర్ కోసం సరిపడా బైట్ల స్థలాన్ని రిజర్వ్ చేస్తుంది.
  3. దశ 3 (Zero Initialization & Constructor Execution): అన్ని ఫీల్డ్‌లకు వాటి డీఫాల్ట్ విలువలను (0, false, null) కేటాయించిన తర్వాత, కన్‌స్ట్రక్టర్‌ను ఎగ్జిక్యూట్ చేసి యూజర్ నిర్దేశించిన విలువలను నింపుతుంది.
  4. దశ 4 (Reference Assignment): హీప్‌లో కొత్తగా సృష్టించబడిన ఆబ్జెక్ట్ యొక్క 64-బిట్ మెమరీ అడ్రస్‌ను స్టాక్ మెమరీలోని c అనే రిఫరెన్స్ వేరియబుల్‌కు అందజేస్తుంది.

4. ఆబ్జెక్ట్ హెడర్: Mark Word & Klass Word ఇంటర్నల్స్ (Deep JVM Memory)

జావా హీప్ మెమరీలో ప్రతి ఆబ్జెక్ట్ మీ డేటా వేరియబుల్స్‌తో పాటు అదనంగా ఆబ్జెక్ట్ హెడర్ (Object Header) అనే వ్యవస్థాపక సమాచారాన్ని కలిగి ఉంటుంది:

// 64-bit JVM Object Structure:
1. Mark Word (8 bytes / 64 bits):
   • Identity HashCode (31 bits)
   • Age for Generational GC (4 bits - max 15 transitions)
   • Biased / Thin / Fat Synchronization Locks (2 bits)

2. Klass Word / Compressed OOPs (4 bytes):
   • ఈ ఆబ్జెక్ట్ ఏ క్లాస్‌కు చెందిందో చెప్పే Metaspace క్లాస్ మెటాడేటా పాయింటర్.

3. Instance Data (Variable bytes): మీ ఫీల్డ్స్ (int, double, references).
4. Padding (0-7 bytes): ఆబ్జెక్ట్ సైజును 8 బైట్ల గుణిజంగా (8-byte alignment) మార్చే ఖాళీ ప్యాడింగ్.

అందువల్ల ఖాళీ క్లాస్ ఆబ్జెక్ట్ (ఎటువంటి ఫీల్డ్స్ లేనిది) కూడా హీప్‌లో కనీసం 16 బైట్ల మెమరీని ఆక్రమిస్తుంది!

5. Instance Variables vs Static Class Variables (Memory Blueprint)

వేరియబుల్ డిక్లరేషన్ వద్ద static కీవర్డ్ చేర్చడం వల్ల మెమరీ కేటాయింపులో పెనుమార్పు సంభవిస్తుంది:

ఫీచర్ / లక్షణం Instance Variable (నాన్-స్టాటిక్) Static Variable (క్లాస్ వేరియబుల్)
మెమరీ కేటాయింపు ప్రతి కొత్త ఆబ్జెక్ట్‌తో పాటు Heap లో ప్రత్యేకంగా పుడుతుంది క్లాస్ లోడ్ అయినప్పుడు Metaspace/Heap లో ఒక్కసారే పుడుతుంది
కాపీల సంఖ్య (Copies) ప్రతి ఆబ్జెక్ట్‌కు ప్రత్యేక కాపీ (N ఆబ్జెక్టులకు N కాపీలు) మొత్తం అప్లికేషన్ మొత్తానికి కేవలం ఒకే ఒక్క కాపీ (Shared)
యాక్సెస్ విధానం ఆబ్జెక్ట్ రిఫరెన్స్ ద్వారా: obj.name క్లాస్ పేరుతో నేరుగా: ClassName.count
జీవితకాలం (Lifetime) ఆబ్జెక్ట్ ఉన్నంతవరకే (GC అయ్యే వరకు) అప్లికేషన్ లేదా JVM ఆగిపోయే వరకు సజీవంగా ఉంటుంది

6. Static Methods & Metaspace ఆర్కిటెక్చర్ (Why static cannot use this)

ఒక మెథడ్‌ను static గా ప్రకటించినప్పుడు, అది ఏ ఒక్క నిర్దిష్ట ఆబ్జెక్ట్‌కు చెందదు. అది నేరుగా క్లాస్‌కు అనుసంధానించబడి ఉంటుంది.

⚠️ గోల్డెన్ రూల్: static మెథడ్ లోపల నుండి నాన్-స్టాటిక్ ఇన్‌స్టాన్స్ వేరియబుల్స్ లేదా మెథడ్లను నేరుగా పిలవడం అసాధ్యం! అలాగే స్టాటిక్ కాంటెక్స్ట్‌లో this లేదా super కీవర్డ్స్ ఉండవు, ఎందుకంటే స్టాటిక్ మెథడ్ కాల్ అయ్యే సమయానికి అసలు ఏ ఆబ్జెక్ట్ ఇంకా పుట్టనే లేదు!

7. ఆబ్జెక్ట్ లైఫ్ సైకిల్ & అనాథ ఆబ్జెక్ట్స్ (Orphan / Unreachable Objects)

హీప్‌లో సృష్టించబడిన ఆబ్జెక్ట్ ఎప్పుడు మరణిస్తుంది? జావాలో మెమరీని మాన్యువల్‌గా ఫ్రీ చేయడానికి C++ లాగా free() లేదా delete ఉండవు.

ఒక ఆబ్జెక్ట్‌ను పాయింట్ చేసే రిఫరెన్స్‌లన్నీ తెగిపోయినప్పుడు, ఆ ఆబ్జెక్ట్‌ను అన్‌రీచబుల్ ఆబ్జెక్ట్ (Unreachable / Orphan Object) అంటారు. ఇది 3 ప్రధాన సందర్భాలలో జరుగుతుంది:

  • 1. రిఫరెన్స్‌ను నల్ చేయడం (Nullifying Reference): acc = null; రాయడం ద్వారా.
  • 2. రిఫరెన్స్‌ను రీ-అసైన్ చేయడం (Reassigning Reference): acc = new BankAccount(); అని కొత్త ఆబ్జెక్ట్ ఇవ్వడం ద్వారా పాతది అనాథగా మారుతుంది.
  • 3. మెథడ్ స్కోప్ ముగియడం (Out of Scope): ఒక మెథడ్ లోపల పుట్టిన లోకల్ ఆబ్జెక్ట్ రిఫరెన్స్, ఆ మెథడ్ ఎగ్జిక్యూషన్ ముగియగానే స్టాక్ నుండి తుడిచిపెట్టుకుపోతుంది.

8. గార్బేజ్ కలెక్షన్ బేసిక్స్: Reachability Analysis (The Silent Cleaner)

జావా యొక్క అత్యంత అద్భుతమైన ఆటోమేషన్ సిస్టమ్ గార్బేజ్ కలెక్టర్ (Garbage Collector - GC). ఇది బ్యాక్‌గ్రౌండ్‌లో లో-ప్రయారిటీ డెమోన్ థ్రెడ్ గా నడుస్తూ హీప్ మెమరీని నిరంతరం పర్యవేక్షిస్తుంది.

ఆధునిక JVM లు GC Roots (యాక్టివ్ థ్రెడ్ స్టాక్ ఫ్రేమ్‌లలోని లోకల్ వేరియబుల్స్, స్టాటిక్ ఫీల్డ్స్, JNI గ్లోబల్ రిఫరెన్సెస్) నుండి మెమరీ గ్రాఫ్‌ను పరిశీలిస్తాయి (Reachability Analysis). GC Roots నుండి చేరుకోలేని ఏ ఆబ్జెక్ట్‌నైనా నిర్దాక్షిణ్యంగా గుర్తించి, దాని మెమరీని తిరిగి హీప్‌కు రీక్లెయిమ్ చేస్తాయి.

9. డెమో 1: Instance vs Static మెమరీ డెమో (State Separation Proof)

ఇన్‌స్టాన్స్ వేరియబుల్స్ ప్రతి ఆబ్జెక్ట్‌కు ఎలా విడివిడిగా ఉంటాయో, మరియు స్టాటిక్ వేరియబుల్ అన్నింటికీ ఎలా ఉమ్మడిగా షేర్ అవుతుందో పరిశీలించే డెమో:

InstanceVsStaticMemoryDemo.java
public class InstanceVsStaticMemoryDemo {

    public static class BankBranch {
        // Static variable: Shared by all branches of the bank
        public static String bankName = "State Financial Bank";
        public static int totalBranchesCount = 0;

        // Instance variables: Unique to each specific branch object
        public String branchCity;
        public double localVaultCash;

        public BankBranch(String city, double initialCash) {
            this.branchCity = city;
            this.localVaultCash = initialCash;
            totalBranchesCount++; // Increment global shared counter
        }

        public void printBranchStatus() {
            System.out.printf("🏦 [%s - %-10s] Local Vault: ₹%,10.2f | Total Bank Branches: %d%n",
                    bankName, branchCity, localVaultCash, totalBranchesCount);
        }
    }

    public static void main(String[] args) {
        System.out.println("=================================================");
        System.out.println("🏛️ INSTANCE VS STATIC MEMORY ARCHITECTURE DEMO");
        System.out.println("=================================================
");

        System.out.println("1. Creating 3 distinct branch objects:");
        BankBranch b1 = new BankBranch("Hyderabad", 500000.0);
        BankBranch b2 = new BankBranch("Bengaluru", 750000.0);
        BankBranch b3 = new BankBranch("Visakhapatnam", 350000.0);

        b1.printBranchStatus();
        b2.printBranchStatus();
        b3.printBranchStatus();

        System.out.println("
2. Modifying static variable BankBranch.bankName:");
        BankBranch.bankName = "NextGen Unified Bank";

        System.out.println("   Modifying b1 local vault cash only (+ ₹1,00,000):");
        b1.localVaultCash += 100000.0;

        System.out.println("
3. Status after modifications:");
        b1.printBranchStatus();
        b2.printBranchStatus();
        b3.printBranchStatus();

        System.out.println("
=================================================");
        System.out.println("✅ తీర్పు: Static వేరియబుల్ మారితే అన్ని ఆబ్జెక్టులలో మారింది,");
        System.out.println("          కానీ Instance వేరియబుల్ కేవలం b1 లో మాత్రమే మారింది!");
        System.out.println("=================================================");
    }
}
Terminal Output:
=================================================
🏛️ INSTANCE VS STATIC MEMORY ARCHITECTURE DEMO
=================================================

1. Creating 3 distinct branch objects:
🏦 [State Financial Bank - Hyderabad ] Local Vault: ₹  5,00,000.00 | Total Bank Branches: 3
🏦 [State Financial Bank - Bengaluru ] Local Vault: ₹  7,50,000.00 | Total Bank Branches: 3
🏦 [State Financial Bank - Visakhapatnam] Local Vault: ₹  3,50,000.00 | Total Bank Branches: 3

2. Modifying static variable BankBranch.bankName:
   Modifying b1 local vault cash only (+ ₹1,00,000):

3. Status after modifications:
🏦 [NextGen Unified Bank - Hyderabad ] Local Vault: ₹  6,00,000.00 | Total Bank Branches: 3
🏦 [NextGen Unified Bank - Bengaluru ] Local Vault: ₹  7,50,000.00 | Total Bank Branches: 3
🏦 [NextGen Unified Bank - Visakhapatnam] Local Vault: ₹  3,50,000.00 | Total Bank Branches: 3

=================================================
✅ తీర్పు: Static వేరియబుల్ మారితే అన్ని ఆబ్జెక్టులలో మారింది,
          కానీ Instance వేరియబుల్ కేవలం b1 లో మాత్రమే మారింది!
=================================================

10. డెమో 2: ఆబ్జెక్ట్ లైఫ్‌సైకిల్ & GC సిమ్యులేషన్ (Object Lifecycle Simulation)

ఆబ్జెక్ట్ రిఫరెన్స్‌ను నల్ చేసినప్పుడు మరియు రీ-అసైన్ చేసినప్పుడు పాత ఆబ్జెక్ట్ ఎలా అన్‌రీచబుల్ అవుతుందో మెమరీ టెలిమెట్రీతో చూపే డెమో:

ObjectLifecycleAndGcSimulation.java
public class ObjectLifecycleAndGcSimulation {

    static class DataNode {
        String payloadId;
        byte[] heavyBuffer = new byte[1024 * 512]; // 512 KB payload

        DataNode(String id) {
            this.payloadId = id;
        }

        @Override
        public String toString() {
            return "DataNode[" + payloadId + "]";
        }
    }

    public static void main(String[] args) {
        System.out.println("=================================================");
        System.out.println("♻️ OBJECT LIFECYCLE & HEAP REALLOCATION DEMO");
        System.out.println("=================================================
");

        Runtime rt = Runtime.getRuntime();

        // Initial free memory
        long initialFree = rt.freeMemory();
        System.out.printf("1. Initial Heap Free Memory: %,d KB%n", initialFree / 1024);

        // Step 1: Allocating first object
        DataNode node1 = new DataNode("Session_Alpha");
        System.out.println("2. Created active reference: " + node1);
        System.out.printf("   Heap Free after node1:    %,d KB%n", rt.freeMemory() / 1024);

        // Step 2: Reassigning reference to a new object (making Session_Alpha orphan)
        System.out.println("
3. Reassigning node1 = new DataNode('Session_Beta')...");
        node1 = new DataNode("Session_Beta");
        System.out.println("   Current active reference: " + node1);
        System.out.println("   ⚠️ 'Session_Alpha' is now UNREACHABLE (Orphan in Heap)!");

        // Step 3: Nullifying reference (making Session_Beta orphan too)
        System.out.println("
4. Nullifying node1 = null...");
        node1 = null;
        System.out.println("   ⚠️ Both objects are now 100% eligible for Garbage Collection!");

        // Triggering GC hint
        System.gc();
        System.out.printf("5. Post-GC Request Free Memory: %,d KB%n", rt.freeMemory() / 1024);

        System.out.println("=================================================");
    }
}
Terminal Output:
=================================================
♻️ OBJECT LIFECYCLE & HEAP REALLOCATION DEMO
=================================================

1. Initial Heap Free Memory: 254,120 KB
2. Created active reference: DataNode[Session_Alpha]
   Heap Free after node1:    253,608 KB

3. Reassigning node1 = new DataNode('Session_Beta')...
   Current active reference: DataNode[Session_Beta]
   ⚠️ 'Session_Alpha' is now UNREACHABLE (Orphan in Heap)!

4. Nullifying node1 = null...
   ⚠️ Both objects are now 100% eligible for Garbage Collection!
5. Post-GC Request Free Memory: 254,116 KB
=================================================

11. Capstone ప్రాజెక్ట్: ఎంటర్‌ప్రైజ్ బ్యాంకింగ్ అకౌంట్ డొమైన్ మోడల్

ఈ అధ్యాయంలో నేర్చుకున్న అన్ని కాన్సెప్టులను (క్లాసులు, ఆబ్జెక్టులు, స్టేట్ & బిహేవియర్, Instance vs Static, మరియు డేటా సేఫ్టీ) సమగ్రంగా మిళితం చేస్తూ ఒక ప్రొడక్షన్-గ్రేడ్ Enterprise Banking Account & Transaction Ledger Domain Engine ను నిర్మిద్దాం:

BankingDomainCoreEngine.java
public class BankingDomainCoreEngine {

    public static class BankAccount {
        // Global Bank Configuration (Static - Shared across all accounts)
        private static final String IFSC_CODE = "APGB0004921";
        private static double annualInterestRate = 6.5; // 6.5% APY
        private static long accountNumberGenerator = 1001002000L;
        private static int activeAccountsTotal = 0;

        // Instance State (Unique to each customer account)
        private final long accountNumber;
        private final String accountHolder;
        private double balance;
        private boolean isFrozen;

        public BankAccount(String holderName, double initialDeposit) {
            this.accountNumber = ++accountNumberGenerator;
            this.accountHolder = holderName;
            this.balance = Math.max(0.0, initialDeposit);
            this.isFrozen = false;
            activeAccountsTotal++;
        }

        // Behavior: Deposit
        public boolean deposit(double amount) {
            if (isFrozen || amount <= 0) {
                System.out.printf("❌ Deposit failed for Acc #%d: Invalid amount or account frozen.%n", accountNumber);
                return false;
            }
            this.balance += amount;
            System.out.printf("✅ Deposited ₹%,.2f into Acc #%d (%s). New Balance: ₹%,.2f%n",
                    amount, accountNumber, accountHolder, balance);
            return true;
        }

        // Behavior: Withdraw with overdraft check
        public boolean withdraw(double amount) {
            if (isFrozen) {
                System.out.printf("❌ Withdrawal denied: Account #%d is frozen.%n", accountNumber);
                return false;
            }
            if (amount <= 0 || amount > this.balance) {
                System.out.printf("❌ Withdrawal failed for Acc #%d: Insufficient funds (Avail: ₹%,.2f, Req: ₹%,.2f)%n",
                        accountNumber, balance, amount);
                return false;
            }
            this.balance -= amount;
            System.out.printf("💸 Withdrawn ₹%,.2f from Acc #%d (%s). Remaining Balance: ₹%,.2f%n",
                    amount, accountNumber, accountHolder, balance);
            return true;
        }

        public void printStatement() {
            System.out.println("-------------------------------------------------");
            System.out.println("📄 APGB OFFICIAL ACCOUNT AUDIT STATEMENT");
            System.out.printf("Account Number: %d | IFSC: %s%n", accountNumber, IFSC_CODE);
            System.out.printf("Holder:         %s%n", accountHolder);
            System.out.printf("Current Status: %s | Annual Interest: %.1f%%%n",
                    (isFrozen ? "FROZEN ❄️" : "ACTIVE 🟢"), annualInterestRate);
            System.out.printf("Liquid Balance: ₹%,.2f%n", balance);
            System.out.println("-------------------------------------------------");
        }

        public static int getActiveAccountsTotal() {
            return activeAccountsTotal;
        }

        public static void updateGlobalInterestRate(double newRate) {
            annualInterestRate = newRate;
            System.out.printf("📢 Global Bank Interest Rate updated to %.2f%% APY for all accounts.%n", newRate);
        }
    }

    public static void main(String[] args) {
        System.out.println("=================================================");
        System.out.println("🏦 ENTERPRISE BANKING CORE DOMAIN ENGINE");
        System.out.println("=================================================
");

        BankAccount acc1 = new BankAccount("Balaji Nemani", 75000.0);
        BankAccount acc2 = new BankAccount("Karthik Verma", 15000.0);

        System.out.println("Total Active Customer Accounts: " + BankAccount.getActiveAccountsTotal() + "
");

        // Performing banking transactions
        acc1.deposit(25000.0);
        acc1.withdraw(15000.0);

        acc2.withdraw(20000.0); // Should fail due to insufficient funds

        // Bank updates interest rate globally
        System.out.println();
        BankAccount.updateGlobalInterestRate(7.25);

        // Printing audit statements
        acc1.printStatement();
        acc2.printStatement();

        System.out.println("=================================================");
    }
}
Terminal Output:
=================================================
🏦 ENTERPRISE BANKING CORE DOMAIN ENGINE
=================================================

Total Active Customer Accounts: 2

✅ Deposited ₹25,000.00 into Acc #1001002001 (Balaji Nemani). New Balance: ₹1,00,000.00
💸 Withdrawn ₹15,000.00 from Acc #1001002001 (Balaji Nemani). Remaining Balance: ₹85,000.00
❌ Withdrawal failed for Acc #1001002002: Insufficient funds (Avail: ₹15,000.00, Req: ₹20,000.00)

📢 Global Bank Interest Rate updated to 7.25% APY for all accounts.
-------------------------------------------------
📄 APGB OFFICIAL ACCOUNT AUDIT STATEMENT
Account Number: 1001002001 | IFSC: APGB0004921
Holder:         Balaji Nemani
Current Status: ACTIVE 🟢 | Annual Interest: 7.2%
Liquid Balance: ₹85,000.00
-------------------------------------------------
-------------------------------------------------
📄 APGB OFFICIAL ACCOUNT AUDIT STATEMENT
Account Number: 1001002002 | IFSC: APGB0004921
Holder:         Karthik Verma
Current Status: ACTIVE 🟢 | Annual Interest: 7.2%
Liquid Balance: ₹15,000.00
-------------------------------------------------
=================================================

12. ప్రొడక్షన్ పిట్‌ఫాల్స్, బెస్ట్ ప్రాక్టీసెస్ & 5 క్విజ్‌లు (Best Practices & Quizzes)

🚫 ప్రొడక్షన్‌లో నివారించాల్సిన 4 ఘోరమైన తప్పులు (Production Pitfalls):

  1. ఆబ్జెక్ట్ రిఫరెన్స్‌తో స్టాటిక్ వేరియబుల్స్ లేదా మెథడ్లను పిలవడం: myAccount.bankName లేదా myAccount.updateRate() అని పిలవడం కోడ్‌ను గందరగోళానికి గురిచేస్తుంది. స్టాటిక్ మెంబర్లను ఎల్లప్పుడూ క్లాస్ పేరుతోనే (BankAccount.bankName) పిలవాలి.
  2. ప్రైవేట్ ఫీల్డ్స్ లేకుండా అన్నింటినీ పబ్లిక్ చేయడం: క్లాస్ ఫీల్డ్స్‌ను public గా ఉంచితే బాహ్య క్లాసులు చెల్లని విలువలను (ఉదా: balance = -50000) నేరుగా నమోదు చేసే ప్రమాదం ఉంది.
  3. స్టాటిక్ కలెక్షన్లలో ఆబ్జెక్టులను వేసి మర్చిపోవడం (Memory Leaks): static List లో ఆబ్జెక్టులను జోడించి తొలగించకపోతే, అవి అప్లికేషన్ ముగిసేవరకు GC కాకుండా మెమరీ లీక్‌ను సృష్టిస్తాయి.
  4. ప్రతిదానికీ System.gc() ను పిలవడం: GC ఎప్పుడు రన్ అవ్వాలో JVM చూసుకుంటుంది. కోడ్‌లో మాన్యువల్‌గా System.gc() పిలిస్తే అనవసరమైన Stop-the-World పాజ్‌లు ఏర్పడతాయి.

✨ ప్రొడక్షన్ గోల్డెన్ రూల్స్ (Golden Rules):

1. డేటా ఎన్‌క్యాప్సులేషన్: క్లాస్ ఫీల్డ్స్ ఎల్లప్పుడూ private గా ఉంచి అవసరమైతేనే getters/setters ఇవ్వండి.
2. స్థిర విలువలకు: క్లాస్ కాన్‌స్టాంట్లను public static final గా ప్రకటించండి.
3. ఆబ్జెక్ట్ ఇమ్మ్యుటబిలిటీ: వీలైనంత వరకు మారకూడని ఫీల్డ్స్‌ను final చేయండి లేదా జావా 14+ Records వాడండి.
4. క్లీన్ బాధ్యత: ప్రతి క్లాస్ ఒకే ఒక డొమైన్ కాన్సెప్ట్‌ను మాత్రమే ప్రతిబింబించాలి.

🧠 మీ అవగాహనను పరీక్షించుకోండి (5 Interactive Quizzes):

ప్రశ్న 1: జావాలో 'new' కీవర్డ్ ద్వారా ఆబ్జెక్ట్ సృష్టించినప్పుడు అది ఎక్కడ కేటాయించబడుతుంది?

సమాధానం: ఆబ్జెక్ట్ ఎల్లప్పుడూ హీప్ మెమరీ (Heap Memory) లోనే కేటాయించబడుతుంది. కేవలం దాని రిఫరెన్స్ వేరియబుల్ మాత్రమే స్టాక్‌లో ఉంటుంది.

ప్రశ్న 2: 64-బిట్ JVM లో ఒక ఆబ్జెక్ట్ హెడర్ లోని Mark Word పరిమాణం ఎంత?

సమాధానం: 8 బైట్లు (64 బిట్లు). ఇందులో హాష్‌కోడ్, GC వయస్సు మరియు లాకింగ్ సమాచారం ఉంటాయి.

ప్రశ్న 3: Instance వేరియబుల్ మరియు Static వేరియబుల్ మధ్య ప్రాథమిక వ్యత్యాసం ఏమిటి?

సమాధానం: Instance వేరియబుల్ ప్రతి ఆబ్జెక్ట్‌కు ప్రత్యేకమైన కాపీని కలిగి ఉంటుంది; Static వేరియబుల్ మొత్తం క్లాస్‌కు సంబంధించిన అన్ని ఆబ్జెక్టులకు కలిపి కేవలం ఒకే ఒక్క ఉమ్మడి కాపీని కలిగి ఉంటుంది.

ప్రశ్న 4: Static మెథడ్ లోపల 'this' కీవర్డ్ ఎందుకు పనిచేయదు?

సమాధానం: Static మెథడ్ క్లాస్ లెవెల్‌లో నడుస్తుంది, ఏ నిర్దిష్ట ఆబ్జెక్ట్‌తో సంబంధం కలిగి ఉండదు. కాబట్టి ప్రస్తుత ఆబ్జెక్ట్‌ను సూచించే this రిఫరెన్స్ అందులో ఉండదు.

ప్రశ్న 5: ఒక ఆబ్జెక్ట్ ఎప్పుడు గార్బేజ్ కలెక్షన్‌కు అర్హత (Eligible for GC) సాధిస్తుంది?

సమాధానం: యాక్టివ్ థ్రెడ్లలోని GC Roots నుండి ఆ ఆబ్జెక్ట్‌ను చేరుకోవడానికి ఎటువంటి లైవ్ రిఫరెన్స్ లేనప్పుడు (Unreachable అయినప్పుడు) అది GC కి అర్హత సాధిస్తుంది.

← మునుపటి పాఠం: 13. Overloading & Varargs తర్వాతి పాఠం: 15. Constructors & this Keyword →