A method is a named, encapsulated collection of statements that performs a specific operation, promotes code reuse (DRY - Don't Repeat Yourself), and improves modularity. In Java, every method must be declared inside a class:
[modifiers] returnType methodName([parameterList]) [throws ExceptionList] { ... }
public, protected, package-private default, private).static, final, synchronized, abstract).void is mandatory.lowerCamelCase naming verbs (e.g., calculateNetPay(), findCustomerById()).(dataType paramName).void transfer(double amount)).transfer(500.00)).Method Overloading allows a class to define multiple methods with the same name but different parameter signatures. It represents compile-time (static) polymorphism, resolved by the compiler during bytecode generation based on argument types.
Overloading is achieved by varying:
add(int a, int b) vs. add(int a, int b, int c)print(int x) vs. print(String s)log(String msg, int code) vs. log(int code, String msg)
Changing the return type alone DOES NOT overload a method!
For example:
int calculate(int x) { return x * 2; }
double calculate(int x) { return x * 2.0; } // COMPILE ERROR: Duplicate method calculate(int)
The compiler cannot distinguish which method to call if the invoker ignores the return value: calculate(5);!
Recursion is a programming technique where a method calls itself directly or indirectly to solve a problem by dividing it into smaller sub-problems. Every valid recursive algorithm mandates two fundamental components:
factorial(1) ➔ Base Case: Returns 1
factorial(2) ➔ 2 * factorial(1) = 2
factorial(3) ➔ 3 * factorial(2) = 6
Each method invocation creates an Activation Record (Stack Frame) on the thread's Call Stack containing local variables, parameters, and the return address. If recursion lacks a base case or recurses too deeply, stack memory is exhausted, throwing a fatal java.lang.StackOverflowError.
One of the most frequently tested concepts in Java interviews is method parameter passing:
account.setBalance(500)) modifies the caller's object.
account = new BankAccount()) rebinds only the local stack variable; the caller's original reference remains completely unchanged!
this Keyword
A constructor is a special member block invoked automatically when an object is instantiated using the new keyword. Its primary purpose is to initialize instance variables and allocate required resources:
void). If you specify a return type, the compiler treats it as an ordinary method!static, final, or abstract.this Keywordthis is an implicit reference variable pointing to the current object instance:
this.balance = balance;.this(...)): Invokes an overloaded constructor within the same class to prevent duplicate initialization code. Rule: this(...) must be the very first statement in the constructor body!this.validate();.this as an argument to other methods or event listeners.
The static keyword denotes that a member belongs to the Class itself rather than to any individual instantiated object:
Math.sqrt()) without allocating an object.
| Characteristic | Static Members | Instance Members |
|---|---|---|
| Memory Allocation | Method Area (Metaspace), once on class load | JVM Heap, allocated per new object |
| Invocation Syntax | ClassName.methodName() |
objectReference.methodName() |
Access to this / super |
Illegal (No object context exists) | Legal (Refers to current object) |
| Access Permissions | Can only access other static members directly | Can access both static and instance members |
This comprehensive application demonstrates all concepts covered in Unit 5:
constructor overloading with this() chaining, static audit transaction counters, overloaded deposit methods, recursive compound interest calculation, and strict pass-by-value reference verification.
/**
* DevAscent Academy — Unit 5 Capstone Project
* Demonstrates Methods, Overloading, Recursion, Constructor Chaining, and Static Members.
*/
public class BankAccountManager {
// Static class-level state: tracks total accounts created across all instances
private static int totalAccountsCreated = 0;
public static final double ANNUAL_INTEREST_RATE = 0.05; // 5% APR
// Instance fields (stored per object on the Heap)
private final String accountNumber;
private final String accountHolder;
private double balance;
// Constructor 1: Default / Minimum Initializer (Chaining via this())
public BankAccountManager(String accountHolder) {
this(accountHolder, 0.0); // Calls Parameterized Constructor
}
// Constructor 2: Parameterized Constructor
public BankAccountManager(String accountHolder, double initialBalance) {
totalAccountsCreated++;
this.accountNumber = "ACCT-" + (1000 + totalAccountsCreated);
this.accountHolder = accountHolder;
this.balance = Math.max(0.0, initialBalance);
}
// Method Overloading: deposit(double)
public void deposit(double amount) {
if (amount > 0) {
this.balance += amount;
System.out.printf("[%s] Deposited: $%.2f | New Balance: $%.2f%n",
this.accountNumber, amount, this.balance);
}
}
// Method Overloading: deposit(double, String) with description memo
public void deposit(double amount, String memo) {
System.out.printf("Transaction Memo: %s -> ", memo);
this.deposit(amount);
}
// Recursion: Recursive Compound Interest Projections
public double projectBalanceRecursively(double principal, int yearsRemaining) {
// Base case: when 0 years remain, projection equals current principal
if (yearsRemaining <= 0) {
return principal;
}
// Recursive case: compound one year's interest and recurse for remaining years
double nextYearPrincipal = principal * (1.0 + ANNUAL_INTEREST_RATE);
return projectBalanceRecursively(nextYearPrincipal, yearsRemaining - 1);
}
// Static Utility Method
public static int getTotalAccountsCreated() {
return totalAccountsCreated;
}
public static void main(String[] args) {
System.out.println("==================================================");
System.out.println(" DEVASCENT ENTERPRISE ACCOUNT MANAGER DEMO ");
System.out.println("==================================================");
// 1. Constructor Chaining Execution
BankAccountManager acct1 = new BankAccountManager("Alice Johnson");
BankAccountManager acct2 = new BankAccountManager("Bob Smith", 5000.00);
// 2. Method Overloading Calls
acct1.deposit(1200.00);
acct2.deposit(850.50, "Quarterly Dividend Payout");
// 3. Recursive Calculation
int projectionYears = 3;
double futureValue = acct2.projectBalanceRecursively(acct2.balance, projectionYears);
System.out.printf("Recursive 3-Year Projection for Bob (5%% APR): $%.2f%n", futureValue);
// 4. Static Class Level Metrics
System.out.println("--------------------------------------------------");
System.out.println("Total Managed Accounts: " + BankAccountManager.getTotalAccountsCreated());
System.out.println("==================================================");
}
}
calculate(10);), the compiler has no contextual mechanism to determine which return type version was intended. Hence, Java considers identical parameter lists with different return types an ambiguous duplicate error.
this(...) follow?this(arguments...). The cardinal rule is that this(...) must be the first line of code in the calling constructor. This guarantees that basic object initialization completes before any custom logic executes.
static method access an instance variable or use the this keyword?static members belong to the class definition loaded into the Method Area, which exists independently of any instantiated objects. Instance variables and this exist only inside specific object instances allocated on the Heap. Because a static method can be invoked when zero objects exist in memory (e.g., ClassName.staticMethod()), there is no this object context to refer to.
obj = new Other()) alters only the local copy on the stack, leaving the caller's original variable untouched.
new MyClass() without arguments, a compile-time error occurs.
StackOverflowError in recursive methods?-Xss), the stack memory becomes completely exhausted, resulting in a fatal java.lang.StackOverflowError.
static keyword; only a single copy exists in the Method Area, shared globally across all instances of the class. Instance Variables are declared without static; each instantiated object on the Heap possesses its own private, isolated copy of those fields.