Java Programming Static Concepts
Core Concept

Java Static Variables, Methods, and Classes

Master Java Static Concepts: Learn static variables, static methods, static classes, static initialization blocks, memory management, utility patterns, and real-world examples.

Static Variables

Class-level storage

Static Methods

Class-level operations

Static Classes

Nested utility classes

Memory Management

Heap vs Stack vs Static

1. Introduction to Static in Java

The static keyword in Java is used for memory management mainly. It indicates that a particular member (variable, method, or class) belongs to the class itself, rather than to instances (objects) of the class.

What is Static?
  • Class-level: Belongs to class, not objects
  • Shared: Single copy shared by all instances
  • No Object Needed: Can access without creating object
  • Early Loading: Loaded when class is loaded
  • Memory Efficiency: Single copy saves memory
  • Lifecycle: Exists for program duration
When to Use Static?
  • Constants: Values that don't change (Math.PI)
  • Counters: Track number of objects created
  • Utility Methods: Math operations, validation
  • Factory Methods: Create objects (getInstance())
  • Singleton Pattern: Ensure single instance
  • Shared Resources: Configuration, cache, pool
  • Main Method: Program entry point

The Static Concept Explained

Think of static members as "class citizens" and instance members as "object citizens". Static members live with the class blueprint, while instance members live with each object created from that blueprint. Just like a factory blueprint (static) vs actual cars produced (instance).

Real-world Analogy

Static = Company Headquarters

  • Shared by all branches (objects)
  • Exists before branches open
  • Single location for entire company
  • Managers can call HQ without visiting a branch
  • Company policies apply to all branches

Instance = Individual Branch

  • Each branch has its own staff, inventory
  • Created when branch opens
  • Independent of other branches
  • Can access HQ resources
  • Has branch-specific data
BasicStaticExample.java
// Demonstrating basic static concepts
class Company {
    // Static variable (class variable)
    static String companyName = "TechCorp Inc.";
    static String headquarters = "Silicon Valley";
    static int totalEmployees = 0;  // Shared by all objects
    
    // Instance variables (object variables)
    String branchName;
    String location;
    int branchEmployees;
    
    // Static block (runs when class is loaded)
    static {
        System.out.println("Company class loaded. Initializing static resources...");
        System.out.println("Company: " + companyName);
        System.out.println("Headquarters: " + headquarters);
    }
    
    // Constructor
    public Company(String branchName, String location, int branchEmployees) {
        this.branchName = branchName;
        this.location = location;
        this.branchEmployees = branchEmployees;
        totalEmployees += branchEmployees;  // Update static variable
        System.out.println("Created branch: " + branchName);
    }
    
    // Static method (class method)
    public static void displayCompanyInfo() {
        System.out.println("\n=== Company Information ===");
        System.out.println("Company Name: " + companyName);
        System.out.println("Headquarters: " + headquarters);
        System.out.println("Total Employees: " + totalEmployees);
        // Cannot access instance variables here!
        // System.out.println(branchName);  // COMPILE ERROR
    }
    
    // Instance method (object method)
    public void displayBranchInfo() {
        System.out.println("\n=== Branch Information ===");
        System.out.println("Branch: " + branchName);
        System.out.println("Location: " + location);
        System.out.println("Branch Employees: " + branchEmployees);
        // Can access static variables
        System.out.println("Company: " + companyName);
        System.out.println("Total Company Employees: " + totalEmployees);
    }
    
    // Another static method
    public static double calculateRevenuePerEmployee(double totalRevenue) {
        if (totalEmployees > 0) {
            return totalRevenue / totalEmployees;
        }
        return 0;
    }
}

public class BasicStaticExample {
    public static void main(String[] args) {
        System.out.println("=== Basic Static Concepts ===\n");
        
        // Access static members WITHOUT creating object
        System.out.println("1. Accessing static members:");
        System.out.println("Company Name: " + Company.companyName);
        System.out.println("Headquarters: " + Company.headquarters);
        Company.displayCompanyInfo();
        
        // Create objects (instances)
        System.out.println("\n2. Creating branches (objects):");
        Company nyBranch = new Company("New York", "Manhattan", 50);
        Company laBranch = new Company("Los Angeles", "Downtown", 75);
        Company chiBranch = new Company("Chicago", "Loop", 40);
        
        // Display branch info
        nyBranch.displayBranchInfo();
        laBranch.displayBranchInfo();
        chiBranch.displayBranchInfo();
        
        // Static variable is shared - all see same value
        System.out.println("\n3. Static variable sharing:");
        System.out.println("Total employees (from NY branch): " + nyBranch.totalEmployees);
        System.out.println("Total employees (from LA branch): " + laBranch.totalEmployees);
        System.out.println("Total employees (from Company class): " + Company.totalEmployees);
        
        // All refer to same memory location
        System.out.println("\n4. Static method usage:");
        double revenue = 10000000.0;
        double revenuePerEmployee = Company.calculateRevenuePerEmployee(revenue);
        System.out.println("Revenue per employee: $" + revenuePerEmployee);
        
        // Update static variable
        System.out.println("\n5. Modifying static variable:");
        Company.totalEmployees += 10;  // Add corporate employees
        System.out.println("Updated total employees: " + Company.totalEmployees);
        
        // Instance variable vs static variable
        System.out.println("\n6. Instance vs Static:");
        System.out.println("Each branch has its own 'branchEmployees':");
        System.out.println("NY: " + nyBranch.branchEmployees);
        System.out.println("LA: " + laBranch.branchEmployees);
        System.out.println("CHI: " + chiBranch.branchEmployees);
        
        System.out.println("\nAll share same 'totalEmployees': " + Company.totalEmployees);
        
        // Cannot call instance method without object
        // Company.displayBranchInfo();  // COMPILE ERROR
        
        // Cannot access instance variable without object
        // System.out.println(Company.branchName);  // COMPILE ERROR
    }
}

2. Static Variables (Class Variables)

Static variables are class-level variables that are shared among all instances of the class. They are initialized only once, at the start of program execution, and exist for the lifetime of the program.

StaticVariablesExample.java
// Comprehensive static variables example
import java.util.ArrayList;
import java.util.List;

class Bank {
    // ========== STATIC VARIABLES ==========
    
    // 1. Static constant (final static)
    public static final String BANK_NAME = "Global Bank";
    public static final double INTEREST_RATE = 4.5;
    public static final int MAX_ACCOUNTS_PER_CUSTOMER = 5;
    
    // 2. Static variable for counting objects
    private static int totalAccountsCreated = 0;
    
    // 3. Static variable for shared resource
    private static double totalBankBalance = 0.0;
    
    // 4. Static collection shared by all instances
    private static List allAccountNumbers = new ArrayList<>();
    
    // 5. Static variable with lazy initialization
    private static BankStatistics statistics = null;
    
    // 6. Static variable for configuration
    private static Configuration config = new Configuration();
    
    // 7. Static variable tracking class state
    private static boolean isBankOpen = true;
    
    // ========== INSTANCE VARIABLES ==========
    private String accountNumber;
    private String accountHolder;
    private double balance;
    private AccountType type;
    
    // ========== CONSTRUCTOR ==========
    public Bank(String accountHolder, double initialBalance, AccountType type) {
        this.accountNumber = generateAccountNumber();
        this.accountHolder = accountHolder;
        this.balance = initialBalance;
        this.type = type;
        
        // Update static variables
        totalAccountsCreated++;
        totalBankBalance += initialBalance;
        allAccountNumbers.add(accountNumber);
        
        System.out.println("Account created: " + accountNumber + 
                          " for " + accountHolder);
    }
    
    // ========== STATIC METHODS ==========
    public static int getTotalAccountsCreated() {
        return totalAccountsCreated;
    }
    
    public static double getTotalBankBalance() {
        return totalBankBalance;
    }
    
    public static List getAllAccountNumbers() {
        // Return copy to prevent modification
        return new ArrayList<>(allAccountNumbers);
    }
    
    public static BankStatistics getStatistics() {
        if (statistics == null) {
            statistics = new BankStatistics();
        }
        return statistics;
    }
    
    public static boolean isBankOpen() {
        return isBankOpen;
    }
    
    public static void closeBank() {
        isBankOpen = false;
        System.out.println("Bank is now closed for the day");
    }
    
    public static void openBank() {
        isBankOpen = true;
        System.out.println("Bank is now open");
    }
    
    // Static utility method
    private static String generateAccountNumber() {
        return "ACC" + (100000 + totalAccountsCreated);
    }
    
    // ========== INSTANCE METHODS ==========
    public void deposit(double amount) {
        if (isBankOpen && amount > 0) {
            balance += amount;
            totalBankBalance += amount;  // Update static variable
            System.out.println("Deposited $" + amount + " to " + accountNumber);
        }
    }
    
    public void withdraw(double amount) {
        if (isBankOpen && amount > 0 && balance >= amount) {
            balance -= amount;
            totalBankBalance -= amount;  // Update static variable
            System.out.println("Withdrew $" + amount + " from " + accountNumber);
        }
    }
    
    public void transfer(Bank recipient, double amount) {
        if (isBankOpen && amount > 0 && balance >= amount) {
            this.balance -= amount;
            recipient.balance += amount;
            // totalBankBalance unchanged (money stays in bank)
            System.out.println("Transferred $" + amount + " from " + 
                             accountNumber + " to " + recipient.accountNumber);
        }
    }
    
    // ========== GETTERS ==========
    public String getAccountNumber() {
        return accountNumber;
    }
    
    public String getAccountHolder() {
        return accountHolder;
    }
    
    public double getBalance() {
        return balance;
    }
    
    public AccountType getType() {
        return type;
    }
    
    @Override
    public String toString() {
        return String.format("Account[%s: %s - $%.2f (%s)]", 
                           accountNumber, accountHolder, balance, type);
    }
}

// ========== SUPPORTING CLASSES ==========
enum AccountType {
    SAVINGS, CHECKING, BUSINESS, STUDENT
}

class BankStatistics {
    private int transactionsToday = 0;
    private double averageBalance = 0.0;
    
    public void recordTransaction() {
        transactionsToday++;
    }
    
    public double calculateAverageBalance() {
        int totalAccounts = Bank.getTotalAccountsCreated();
        if (totalAccounts > 0) {
            return Bank.getTotalBankBalance() / totalAccounts;
        }
        return 0.0;
    }
    
    public void displayStatistics() {
        System.out.println("\n=== Bank Statistics ===");
        System.out.println("Total Accounts: " + Bank.getTotalAccountsCreated());
        System.out.println("Total Bank Balance: $" + Bank.getTotalBankBalance());
        System.out.println("Average Balance: $" + calculateAverageBalance());
        System.out.println("Transactions Today: " + transactionsToday);
        System.out.println("Bank Open: " + Bank.isBankOpen());
    }
}

class Configuration {
    private int maxWithdrawalLimit = 5000;
    private double overdraftFee = 35.0;
    private String currency = "USD";
    
    public int getMaxWithdrawalLimit() {
        return maxWithdrawalLimit;
    }
    
    public double getOverdraftFee() {
        return overdraftFee;
    }
    
    public String getCurrency() {
        return currency;
    }
}

public class StaticVariablesExample {
    public static void main(String[] args) {
        System.out.println("=== Static Variables (Class Variables) ===\n");
        
        System.out.println("1. Accessing static constants:");
        System.out.println("Bank Name: " + Bank.BANK_NAME);
        System.out.println("Interest Rate: " + Bank.INTEREST_RATE + "%");
        System.out.println("Max Accounts: " + Bank.MAX_ACCOUNTS_PER_CUSTOMER);
        
        System.out.println("\n2. Creating bank accounts:");
        Bank account1 = new Bank("Alice Johnson", 5000.0, AccountType.SAVINGS);
        Bank account2 = new Bank("Bob Smith", 3000.0, AccountType.CHECKING);
        Bank account3 = new Bank("Charlie Brown", 10000.0, AccountType.BUSINESS);
        
        System.out.println("\n3. Static variable sharing demonstration:");
        System.out.println("Total accounts created: " + Bank.getTotalAccountsCreated());
        System.out.println("Total bank balance: $" + Bank.getTotalBankBalance());
        
        System.out.println("\n4. Performing transactions:");
        account1.deposit(1000.0);
        account2.withdraw(500.0);
        account3.transfer(account1, 2000.0);
        
        System.out.println("\n5. After transactions:");
        System.out.println("Total bank balance: $" + Bank.getTotalBankBalance());
        System.out.println("Account 1 balance: $" + account1.getBalance());
        System.out.println("Account 2 balance: $" + account2.getBalance());
        System.out.println("Account 3 balance: $" + account3.getBalance());
        
        System.out.println("\n6. Shared static collection:");
        List allAccounts = Bank.getAllAccountNumbers();
        System.out.println("All account numbers: " + allAccounts);
        
        System.out.println("\n7. Singleton pattern with static variable:");
        BankStatistics stats1 = Bank.getStatistics();
        BankStatistics stats2 = Bank.getStatistics();
        System.out.println("Same statistics object? " + (stats1 == stats2));
        stats1.recordTransaction();
        stats1.recordTransaction();
        stats1.displayStatistics();
        
        System.out.println("\n8. Static variable for class state:");
        System.out.println("Bank open? " + Bank.isBankOpen());
        Bank.closeBank();
        System.out.println("Bank open? " + Bank.isBankOpen());
        
        // Try transaction when bank is closed
        account1.deposit(100.0);  // Should not work
        
        Bank.openBank();
        account1.deposit(100.0);  // Should work now
        
        System.out.println("\n9. Memory demonstration:");
        System.out.println("Each Bank object has:");
        System.out.println("  - Instance variables: accountNumber, accountHolder, balance, type");
        System.out.println("  - Shared static variables: totalAccountsCreated, totalBankBalance, etc.");
        System.out.println("\nMemory layout:");
        System.out.println("Heap: 3 Bank objects (each ~40 bytes)");
        System.out.println("Static Area: 1 copy of static variables");
        System.out.println("Total memory: ~120 bytes (heap) + ~50 bytes (static)");
        System.out.println("Without static, would need: ~170 bytes * 3 = 510 bytes");
        
        System.out.println("\n10. Creating more accounts to see counter:");
        Bank account4 = new Bank("Diana Prince", 7500.0, AccountType.SAVINGS);
        Bank account5 = new Bank("Ethan Hunt", 2500.0, AccountType.STUDENT);
        
        System.out.println("\nFinal statistics:");
        stats1.displayStatistics();
        
        System.out.println("\n=== Static Variable Rules ===");
        System.out.println("1. Single copy shared by all instances");
        System.out.println("2. Loaded when class is loaded (before object creation)");
        System.out.println("3. Can be accessed without object: ClassName.variable");
        System.out.println("4. Can be accessed with object: object.variable (not recommended)");
        System.out.println("5. Default value based on type (0, null, false)");
        System.out.println("6. Can be public, private, protected, or default");
        System.out.println("7. Can be final (constant)");
        System.out.println("8. Exist for program lifetime");
    }
}

Static Variables - Rules & Characteristics

Feature Static Variable Instance Variable Explanation
Declaration static type name; type name; Static keyword required
Memory Static area (method area) Heap (with object) Different memory locations
Copies One per class One per object Static shared, instance unique
Loading Time When class loads When object creates Static earlier than instance
Access ClassName.variable object.variable Static doesn't need object
Lifetime Program duration Object lifetime Static lives longer
Default Value Based on type Based on type Both get default values
Scope Class level Object level Different scopes
Use Case Counters, constants, shared resources Object state, individual properties Different purposes
Thread Safety Not thread-safe (shared) Thread-safe per object Static requires synchronization
Memory Layout: Static vs Instance Variables
Static Memory Area
BANK_NAME = "Global Bank"
INTEREST_RATE = 4.5
totalAccountsCreated = 5
totalBankBalance = 29000.0
allAccountNumbers [List]

Single copy for entire class

Heap Memory (Object 1)
accountNumber = "ACC100001"
accountHolder = "Alice"
balance = 8000.0
type = SAVINGS

Unique to each object

Heap Memory (Object 2)
accountNumber = "ACC100002"
accountHolder = "Bob"
balance = 2500.0
type = CHECKING

Unique to each object

Key Points:

  • Static variables: One copy in static memory area
  • Instance variables: Each object has its own copy in heap
  • All objects reference the same static variables
  • Static area exists when class loads, heap objects exist when created

3. Static Methods (Class Methods)

Static methods belong to the class rather than any object instance. They can be called without creating an object of the class and can only access static members directly.

StaticMethodsExample.java
// Comprehensive static methods example
import java.util.Arrays;

class MathUtils {
    // Static constants
    public static final double PI = 3.141592653589793;
    public static final double E = 2.718281828459045;
    public static final double GOLDEN_RATIO = 1.618033988749895;
    
    // Static variable for method call tracking
    private static int methodCallCount = 0;
    
    // ========== STATIC METHODS ==========
    
    // 1. Basic static method
    public static double add(double a, double b) {
        methodCallCount++;
        return a + b;
    }
    
    public static double subtract(double a, double b) {
        methodCallCount++;
        return a - b;
    }
    
    public static double multiply(double a, double b) {
        methodCallCount++;
        return a * b;
    }
    
    public static double divide(double a, double b) {
        methodCallCount++;
        if (b == 0) {
            throw new IllegalArgumentException("Division by zero");
        }
        return a / b;
    }
    
    // 2. Static method with array parameter
    public static double average(double... numbers) {
        methodCallCount++;
        if (numbers == null || numbers.length == 0) {
            return 0.0;
        }
        double sum = 0.0;
        for (double num : numbers) {
            sum += num;
        }
        return sum / numbers.length;
    }
    
    // 3. Static method returning complex object
    public static Statistics calculateStatistics(double[] data) {
        methodCallCount++;
        if (data == null || data.length == 0) {
            return new Statistics(0, 0, 0, 0);
        }
        
        double sum = 0.0;
        double min = data[0];
        double max = data[0];
        
        for (double value : data) {
            sum += value;
            if (value < min) min = value;
            if (value > max) max = value;
        }
        
        double mean = sum / data.length;
        return new Statistics(sum, mean, min, max);
    }
    
    // 4. Static factory method
    public static Circle createCircle(double radius) {
        methodCallCount++;
        return new Circle(radius);
    }
    
    public static Rectangle createRectangle(double width, double height) {
        methodCallCount++;
        return new Rectangle(width, height);
    }
    
    // 5. Static method with generic type
    public static  boolean contains(T[] array, T element) {
        methodCallCount++;
        if (array == null) return false;
        for (T item : array) {
            if (item == null && element == null) return true;
            if (item != null && item.equals(element)) return true;
        }
        return false;
    }
    
    // 6. Static method that calls other static methods
    public static double circleArea(double radius) {
        methodCallCount++;
        return multiply(PI, multiply(radius, radius));
    }
    
    public static double circleCircumference(double radius) {
        methodCallCount++;
        return multiply(2, multiply(PI, radius));
    }
    
    // 7. Static method with recursion
    public static int factorial(int n) {
        methodCallCount++;
        if (n < 0) {
            throw new IllegalArgumentException("Factorial undefined for negative numbers");
        }
        if (n == 0 || n == 1) {
            return 1;
        }
        return n * factorial(n - 1);
    }
    
    // 8. Static method with validation
    public static boolean isValidEmail(String email) {
        methodCallCount++;
        if (email == null || email.isEmpty()) {
            return false;
        }
        // Simple email validation
        return email.contains("@") && 
               email.contains(".") && 
               email.indexOf("@") < email.lastIndexOf(".");
    }
    
    // 9. Static utility method
    public static String formatCurrency(double amount) {
        methodCallCount++;
        return String.format("$%.2f", amount);
    }
    
    // 10. Static method that throws exception
    public static double sqrt(double number) throws IllegalArgumentException {
        methodCallCount++;
        if (number < 0) {
            throw new IllegalArgumentException("Cannot calculate square root of negative number");
        }
        return Math.sqrt(number);
    }
    
    // Static getter for static variable
    public static int getMethodCallCount() {
        return methodCallCount;
    }
    
    public static void resetMethodCallCount() {
        methodCallCount = 0;
    }
    
    // CANNOT have instance methods here (no 'this' reference)
    // public void instanceMethod() { }  // Would need non-static context
    
    // ========== STATIC NESTED CLASSES ==========
    static class Circle {
        private double radius;
        
        public Circle(double radius) {
            this.radius = radius;
        }
        
        public double getArea() {
            return MathUtils.circleArea(radius);
        }
        
        public double getCircumference() {
            return MathUtils.circleCircumference(radius);
        }
    }
    
    static class Rectangle {
        private double width;
        private double height;
        
        public Rectangle(double width, double height) {
            this.width = width;
            this.height = height;
        }
        
        public double getArea() {
            return multiply(width, height);
        }
        
        public double getPerimeter() {
            return multiply(2, add(width, height));
        }
    }
    
    static class Statistics {
        private double sum;
        private double mean;
        private double min;
        private double max;
        
        public Statistics(double sum, double mean, double min, double max) {
            this.sum = sum;
            this.mean = mean;
            this.min = min;
            this.max = max;
        }
        
        @Override
        public String toString() {
            return String.format("Sum: %.2f, Mean: %.2f, Min: %.2f, Max: %.2f", 
                               sum, mean, min, max);
        }
    }
}

// Another example: String utilities
class StringUtils {
    // Private constructor to prevent instantiation
    private StringUtils() {
        throw new UnsupportedOperationException("Utility class - cannot be instantiated");
    }
    
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }
    
    public static String reverse(String str) {
        if (str == null) return null;
        return new StringBuilder(str).reverse().toString();
    }
    
    public static boolean isPalindrome(String str) {
        if (str == null) return false;
        String cleaned = str.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
        return cleaned.equals(reverse(cleaned));
    }
    
    public static int countWords(String str) {
        if (isNullOrEmpty(str)) return 0;
        return str.trim().split("\\s+").length;
    }
}

// Singleton pattern using static method
class ConfigurationManager {
    // Static variable for singleton instance
    private static ConfigurationManager instance;
    
    // Private constructor
    private ConfigurationManager() {
        // Load configuration
        System.out.println("ConfigurationManager initialized");
    }
    
    // Static factory method (singleton pattern)
    public static ConfigurationManager getInstance() {
        if (instance == null) {
            instance = new ConfigurationManager();
        }
        return instance;
    }
    
    public void loadConfig() {
        System.out.println("Loading configuration...");
    }
}

public class StaticMethodsExample {
    public static void main(String[] args) {
        System.out.println("=== Static Methods (Class Methods) ===\n");
        
        System.out.println("1. Basic math operations:");
        System.out.println("5 + 3 = " + MathUtils.add(5, 3));
        System.out.println("10 - 4 = " + MathUtils.subtract(10, 4));
        System.out.println("6 * 7 = " + MathUtils.multiply(6, 7));
        System.out.println("15 / 3 = " + MathUtils.divide(15, 3));
        
        System.out.println("\n2. Using static constants:");
        System.out.println("PI = " + MathUtils.PI);
        System.out.println("E = " + MathUtils.E);
        System.out.println("Golden Ratio = " + MathUtils.GOLDEN_RATIO);
        
        System.out.println("\n3. Array operations:");
        double[] numbers = {2.5, 3.7, 1.8, 4.2, 5.1};
        System.out.println("Average: " + MathUtils.average(numbers));
        System.out.println("Statistics: " + MathUtils.calculateStatistics(numbers));
        
        System.out.println("\n4. Factory methods:");
        MathUtils.Circle circle = MathUtils.createCircle(5.0);
        MathUtils.Rectangle rect = MathUtils.createRectangle(4.0, 6.0);
        System.out.println("Circle area: " + circle.getArea());
        System.out.println("Rectangle area: " + rect.getArea());
        
        System.out.println("\n5. Generic method:");
        String[] fruits = {"Apple", "Banana", "Orange"};
        System.out.println("Contains 'Banana'? " + MathUtils.contains(fruits, "Banana"));
        System.out.println("Contains 'Grape'? " + MathUtils.contains(fruits, "Grape"));
        
        System.out.println("\n6. Recursive method:");
        System.out.println("Factorial of 5: " + MathUtils.factorial(5));
        
        System.out.println("\n7. Validation methods:");
        System.out.println("Is 'test@email.com' valid? " + MathUtils.isValidEmail("test@email.com"));
        System.out.println("Is 'invalid' valid? " + MathUtils.isValidEmail("invalid"));
        
        System.out.println("\n8. String utilities (pure static class):");
        System.out.println("Is null or empty? " + StringUtils.isNullOrEmpty(""));
        System.out.println("Reverse 'hello': " + StringUtils.reverse("hello"));
        System.out.println("Is 'racecar' palindrome? " + StringUtils.isPalindrome("racecar"));
        System.out.println("Word count: " + StringUtils.countWords("Java is awesome"));
        
        // Try to instantiate StringUtils (should fail)
        // StringUtils utils = new StringUtils();  // COMPILE ERROR
        
        System.out.println("\n9. Singleton pattern with static method:");
        ConfigurationManager config1 = ConfigurationManager.getInstance();
        ConfigurationManager config2 = ConfigurationManager.getInstance();
        System.out.println("Same instance? " + (config1 == config2));
        config1.loadConfig();
        
        System.out.println("\n10. Method call tracking:");
        System.out.println("Total method calls: " + MathUtils.getMethodCallCount());
        MathUtils.resetMethodCallCount();
        System.out.println("After reset: " + MathUtils.getMethodCallCount());
        
        // Demonstrate what CANNOT be done
        System.out.println("\n=== Static Method Restrictions ===");
        System.out.println("1. Cannot access instance variables directly");
        System.out.println("2. Cannot call instance methods directly");
        System.out.println("3. Cannot use 'this' or 'super' keywords");
        System.out.println("4. Can only directly access other static members");
        
        System.out.println("\n=== When to Use Static Methods ===");
        System.out.println("✅ Utility/helper methods (MathUtils, StringUtils)");
        System.out.println("✅ Factory methods (create objects)");
        System.out.println("✅ Singleton getInstance() method");
        System.out.println("✅ Main method (program entry point)");
        System.out.println("✅ Methods that don't need object state");
        System.out.println("✅ Methods that operate only on parameters");
        
        System.out.println("\n=== When NOT to Use Static Methods ===");
        System.out.println("❌ Methods that need object state");
        System.out.println("❌ Methods that override/implement");
        System.out.println("❌ Methods using polymorphism");
        System.out.println("❌ Methods that modify object state");
    }
}

Static Methods vs Instance Methods

Aspect Static Method Instance Method
Keyword static in declaration No static keyword
Belongs to Class Object (instance)
Calling ClassName.method() object.method()
Memory Loaded with class Loaded with object
Access to Only static members Both static and instance
this/super Cannot use Can use
Overriding Cannot be overridden Can be overridden
Polymorphism No (compile-time binding) Yes (runtime binding)
Use Case Utilities, factories Object behavior
Static Method Restrictions
  • Cannot directly access instance variables
  • Cannot directly call instance methods
  • Cannot use 'this' or 'super' keywords
  • Cannot be abstract (except in interfaces)
  • Cannot be synchronized on instance
  • Early binding (compile-time polymorphism)
  • Cannot be overridden (but can be hidden)
When to Use Static Methods
  • Utility/helper methods (Math.abs())
  • Factory methods (Calendar.getInstance())
  • Singleton pattern (getInstance())
  • Main method entry point
  • Methods that don't need object state
  • Methods that only work with parameters
  • Performance-critical code (no object creation)
StaticMethodMistakes.java
// Common mistakes with static methods
class Employee {
    private String name;  // Instance variable
    private int id;       // Instance variable
    private static int totalEmployees = 0;  // Static variable
    
    public Employee(String name, int id) {
        this.name = name;
        this.id = id;
        totalEmployees++;
    }
    
    // Instance method - OK
    public void displayInfo() {
        System.out.println("Name: " + name);
        System.out.println("ID: " + id);
        System.out.println("Total Employees: " + totalEmployees);
    }
    
    // Static method - COMMON MISTAKES:
    
    // MISTAKE 1: Trying to access instance variables
    /*
    public static void printName() {
        System.out.println(name);  // COMPILE ERROR!
        // Cannot make static reference to non-static field
    }
    */
    
    // MISTAKE 2: Trying to call instance method
    /*
    public static void callDisplay() {
        displayInfo();  // COMPILE ERROR!
        // Cannot make static reference to non-static method
    }
    */
    
    // MISTAKE 3: Using 'this' keyword
    /*
    public static void printThis() {
        System.out.println(this.name);  // COMPILE ERROR!
        // Cannot use 'this' in static context
    }
    */
    
    // CORRECT: Accessing static variable
    public static void printTotalEmployees() {
        System.out.println("Total Employees: " + totalEmployees);  // OK
    }
    
    // CORRECT: Can access instance through parameter
    public static void printEmployeeInfo(Employee emp) {
        System.out.println("Name: " + emp.name);  // OK - has object reference
        System.out.println("ID: " + emp.id);      // OK - has object reference
    }
}

// Method hiding vs overriding
class Parent {
    public static void staticMethod() {
        System.out.println("Parent static method");
    }
    
    public void instanceMethod() {
        System.out.println("Parent instance method");
    }
}

class Child extends Parent {
    // This HIDES the parent static method (not override)
    public static void staticMethod() {
        System.out.println("Child static method");
    }
    
    // This OVERRIDES the parent instance method
    @Override
    public void instanceMethod() {
        System.out.println("Child instance method");
    }
}

public class StaticMethodMistakes {
    public static void main(String[] args) {
        System.out.println("=== Common Static Method Mistakes ===\n");
        
        Employee emp1 = new Employee("Alice", 101);
        Employee emp2 = new Employee("Bob", 102);
        
        // Correct usage
        Employee.printTotalEmployees();
        Employee.printEmployeeInfo(emp1);
        
        // Method hiding demonstration
        System.out.println("\n=== Method Hiding vs Overriding ===");
        Parent parent = new Parent();
        Child child = new Child();
        Parent parentRefToChild = new Child();
        
        // Static method - compile-time binding
        parent.staticMethod();           // Parent static method
        child.staticMethod();            // Child static method
        parentRefToChild.staticMethod(); // Parent static method (HIDING)
        
        // Instance method - runtime binding
        parent.instanceMethod();           // Parent instance method
        child.instanceMethod();            // Child instance method
        parentRefToChild.instanceMethod(); // Child instance method (OVERRIDING)
        
        System.out.println("\n=== Key Points ===");
        System.out.println("1. Static methods are bound at compile-time");
        System.out.println("2. Instance methods are bound at runtime");
        System.out.println("3. Static method in subclass HIDES parent method");
        System.out.println("4. Instance method in subclass OVERRIDES parent method");
        System.out.println("5. Reference type determines static method call");
        System.out.println("6. Object type determines instance method call");
    }
}

4. Static Classes & Nested Static Classes

In Java, static classes are nested classes declared as static. They don't have access to instance members of the outer class and can be instantiated without an instance of the outer class.

StaticClassesExample.java
// Comprehensive static classes example

// ========== OUTER CLASS ==========
class University {
    // Static variables of outer class
    private static String universityName = "Tech University";
    private static int establishedYear = 1950;
    private static int totalStudents = 0;
    
    // Instance variables
    private String departmentName;
    private int departmentStudents;
    
    // Constructor
    public University(String departmentName, int departmentStudents) {
        this.departmentName = departmentName;
        this.departmentStudents = departmentStudents;
        totalStudents += departmentStudents;
    }
    
    // ========== STATIC NESTED CLASS ==========
    // Can be public, private, protected, or package-private
    public static class Student {
        // Can have its own static variables
        private static int nextStudentId = 1000;
        
        // Instance variables
        private int studentId;
        private String name;
        private String major;
        private double gpa;
        
        // Constructor
        public Student(String name, String major) {
            this.studentId = nextStudentId++;
            this.name = name;
            this.major = major;
            this.gpa = 0.0;
        }
        
        // Can access static members of outer class DIRECTLY
        public void displayUniversityInfo() {
            System.out.println("University: " + universityName);
            System.out.println("Established: " + establishedYear);
            System.out.println("Total Students: " + totalStudents);
        }
        
        // CANNOT access instance members of outer class
        /*
        public void displayDepartmentInfo() {
            System.out.println(departmentName);  // COMPILE ERROR!
            // Cannot make static reference to non-static field
        }
        */
        
        // Instance methods
        public void enroll() {
            System.out.println(name + " (ID: " + studentId + 
                             ") enrolled in " + major);
        }
        
        public void updateGPA(double newGPA) {
            this.gpa = newGPA;
            System.out.println(name + "'s GPA updated to: " + gpa);
        }
        
        // Static method in static nested class
        public static int getNextStudentId() {
            return nextStudentId;
        }
        
        // Getters
        public int getStudentId() { return studentId; }
        public String getName() { return name; }
        public String getMajor() { return major; }
        public double getGpa() { return gpa; }
        
        @Override
        public String toString() {
            return String.format("Student[%d: %s - %s (GPA: %.2f)]", 
                               studentId, name, major, gpa);
        }
    }
    
    // ========== ANOTHER STATIC NESTED CLASS ==========
    private static class Statistics {
        // Private static nested class - only accessible within University
        private static int graduatesThisYear = 0;
        
        public static void recordGraduation() {
            graduatesThisYear++;
            totalStudents--;  // Can access outer class static variable
        }
        
        public static void displayStatistics() {
            System.out.println("\n=== University Statistics ===");
            System.out.println("University: " + universityName);
            System.out.println("Total Students: " + totalStudents);
            System.out.println("Graduates This Year: " + graduatesThisYear);
            System.out.println("Next Student ID: " + Student.getNextStudentId());
        }
    }
    
    // ========== STATIC NESTED ENUM ==========
    public static enum DegreeType {
        BACHELOR("Bachelor's Degree", 4),
        MASTER("Master's Degree", 2),
        DOCTORATE("Doctorate", 4),
        ASSOCIATE("Associate Degree", 2);
        
        private final String displayName;
        private final int typicalYears;
        
        DegreeType(String displayName, int typicalYears) {
            this.displayName = displayName;
            this.typicalYears = typicalYears;
        }
        
        public String getDisplayName() {
            return displayName;
        }
        
        public int getTypicalYears() {
            return typicalYears;
        }
    }
    
    // ========== OUTER CLASS METHODS ==========
    public void displayDepartmentInfo() {
        System.out.println("\n=== Department Info ===");
        System.out.println("Department: " + departmentName);
        System.out.println("Students: " + departmentStudents);
        System.out.println("University: " + universityName);
        
        // Can access static nested classes
        Statistics.displayStatistics();
    }
    
    public void graduateStudent(Student student) {
        System.out.println("\n" + student.getName() + " is graduating!");
        Statistics.recordGraduation();
        departmentStudents--;
    }
    
    // Static method in outer class
    public static void displayUniversityOverview() {
        System.out.println("\n=== University Overview ===");
        System.out.println("Name: " + universityName);
        System.out.println("Established: " + establishedYear);
        System.out.println("Total Students: " + totalStudents);
        
                // Can create instances of static nested class
        Student prospective = new Student("Prospective", "Undecided");
        System.out.println("Next available ID: " + Student.getNextStudentId());
    }
}

// ========== EXAMPLE OF COMPLETE UTILITY CLASS ==========
// Often used for organization and encapsulation
final class MathConstants {
    // Private constructor to prevent instantiation
    private MathConstants() {
        throw new AssertionError("Cannot instantiate utility class");
    }
    
    // Static nested class for geometric constants
    public static class Geometry {
        public static final double PI = 3.141592653589793;
        public static final double E = 2.718281828459045;
        public static final double GOLDEN_RATIO = 1.618033988749895;
        
        // Private constructor for nested static class too
        private Geometry() {}
    }
    
    // Static nested class for physics constants
    public static class Physics {
        public static final double GRAVITY = 9.80665;
        public static final double LIGHT_SPEED = 299792458;
        public static final double PLANCK = 6.62607015e-34;
        
        private Physics() {}
    }
    
    // Static nested class for conversion factors
    public static class Conversions {
        public static final double INCH_TO_CM = 2.54;
        public static final double POUND_TO_KG = 0.453592;
        public static final double MILE_TO_KM = 1.60934;
        
        private Conversions() {}
    }
}

// ========== BUILDER PATTERN WITH STATIC NESTED CLASS ==========
class Computer {
    private final String cpu;
    private final int ram;
    private final int storage;
    private final boolean hasGraphicsCard;
    private final String operatingSystem;
    
    // Private constructor
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
        this.hasGraphicsCard = builder.hasGraphicsCard;
        this.operatingSystem = builder.operatingSystem;
    }
    
    // Static nested Builder class
    public static class Builder {
        // Required parameters
        private final String cpu;
        private final int ram;
        
        // Optional parameters - initialized to default values
        private int storage = 256;
        private boolean hasGraphicsCard = false;
        private String operatingSystem = "Windows 10";
        
        // Constructor for required fields
        public Builder(String cpu, int ram) {
            this.cpu = cpu;
            this.ram = ram;
        }
        
        // Setters for optional parameters (return Builder for chaining)
        public Builder storage(int storage) {
            this.storage = storage;
            return this;
        }
        
        public Builder graphicsCard(boolean hasGraphicsCard) {
            this.hasGraphicsCard = hasGraphicsCard;
            return this;
        }
        
        public Builder operatingSystem(String operatingSystem) {
            this.operatingSystem = operatingSystem;
            return this;
        }
        
        // Build method
        public Computer build() {
            return new Computer(this);
        }
    }
    
    // Getters
    public String getCpu() { return cpu; }
    public int getRam() { return ram; }
    public int getStorage() { return storage; }
    public boolean hasGraphicsCard() { return hasGraphicsCard; }
    public String getOperatingSystem() { return operatingSystem; }
    
    @Override
    public String toString() {
        return String.format("Computer[CPU: %s, RAM: %dGB, Storage: %dGB, GPU: %s, OS: %s]",
                cpu, ram, storage, hasGraphicsCard ? "Yes" : "No", operatingSystem);
    }
}

public class StaticClassesExample {
    public static void main(String[] args) {
        System.out.println("=== Static Classes & Nested Static Classes ===\n");
        
        System.out.println("1. Creating University departments:");
        University csDept = new University("Computer Science", 300);
        University engDept = new University("Engineering", 250);
        
        System.out.println("\n2. Creating Students (using static nested class):");
        // Note: Can create Student without University instance
        University.Student student1 = new University.Student("Alice", "Computer Science");
        University.Student student2 = new University.Student("Bob", "Engineering");
        University.Student student3 = new University.Student("Charlie", "Mathematics");
        
        student1.enroll();
        student2.enroll();
        student3.enroll();
        
        student1.updateGPA(3.8);
        student2.updateGPA(3.5);
        student3.updateGPA(3.9);
        
        System.out.println("\n3. Students accessing university info:");
        student1.displayUniversityInfo();
        
        System.out.println("\n4. Using static nested enum:");
        University.DegreeType bachelors = University.DegreeType.BACHELOR;
        University.DegreeType masters = University.DegreeType.MASTER;
        
        System.out.println(bachelors.getDisplayName() + " typically takes " + 
                         bachelors.getTypicalYears() + " years");
        System.out.println(masters.getDisplayName() + " typically takes " + 
                         masters.getTypicalYears() + " years");
        
        System.out.println("\n5. Department displaying info:");
        csDept.displayDepartmentInfo();
        
        System.out.println("\n6. University static method:");
        University.displayUniversityOverview();
        
        System.out.println("\n7. Using MathConstants utility class:");
        System.out.println("PI: " + MathConstants.Geometry.PI);
        System.out.println("Gravity: " + MathConstants.Physics.GRAVITY);
        System.out.println("Inch to CM: " + MathConstants.Conversions.INCH_TO_CM);
        
        // Try to instantiate (should be prevented by private constructor)
        // MathConstants constants = new MathConstants(); // COMPILE ERROR
        
        System.out.println("\n8. Builder pattern with static nested class:");
        Computer gamingPC = new Computer.Builder("Intel i9", 32)
                .storage(1000)
                .graphicsCard(true)
                .operatingSystem("Windows 11")
                .build();
        
        Computer officePC = new Computer.Builder("Intel i5", 16)
                .operatingSystem("Ubuntu 22.04")
                .build();
        
        System.out.println("Gaming PC: " + gamingPC);
        System.out.println("Office PC: " + officePC);
        
        System.out.println("\n=== Key Characteristics of Static Nested Classes ===");
        System.out.println("1. Can be instantiated without outer class instance");
        System.out.println("2. Can access outer class STATIC members directly");
        System.out.println("3. CANNOT access outer class INSTANCE members directly");
        System.out.println("4. Can be public, private, protected, or package-private");
        System.out.println("5. Can have static and instance members");
        System.out.println("6. Useful for logical grouping, encapsulation");
        System.out.println("7. Commonly used for Builder pattern, constants, utilities");
        
        System.out.println("\n=== When to Use Static Nested Classes ===");
        System.out.println("✅ Builder pattern implementation");
        System.out.println("✅ Constants organization (MathConstants.Geometry.PI)");
        System.out.println("✅ Utility classes within a class");
        System.out.println("✅ Node classes in data structures");
        System.out.println("✅ Related classes that don't need outer instance");
        System.out.println("✅ Enum definitions within a class");
        
        System.out.println("\n=== Memory Considerations ===");
        System.out.println("Static nested classes don't hold reference to outer instance");
        System.out.println("More memory efficient than non-static inner classes");
        System.out.println("Can be serialized independently");
    }
}