Learn Object-Oriented Programming through a real Bank User class β fields, methods, constructors, and more.
A class is a blueprint β it defines what data and behavior a type has. An instance (object) is a real thing created from that blueprint. Think of a class as a cookie cutter and instances as the cookies.
Defined once. Describes the shape, fields, and methods. Lives in a .java file. Does not hold actual data β it's just a template.
Created with new. Each instance has its own copy of the fields with real values. You can create as many as you want.
// One class, two completely independent objects
BankUser alice = new BankUser("Alice", "ACC001", 5000.0);
BankUser bob = new BankUser("Bob", "ACC002", 1200.0);
// They share the class blueprint, but NOT data
System.out.println(alice.getBalance()); // 5000.0
System.out.println(bob.getBalance()); // 1200.0
Fields store the state of an object. Each instance has its own copy. They're usually declared private to protect data β this is called encapsulation.
public class BankUser {
// ββ FIELDS βββββββββββββββββββββββββββββββββββββββββ
// private = only accessible inside this class
private String name; // account holder name
private String accountId; // unique ID like "ACC001"
private double balance; // current balance in $
private boolean isActive; // account open/closed flag
// static field = shared by ALL instances (class-level)
private static int totalAccounts = 0;
}
Declared without static. Each object gets its OWN copy. alice.balance and bob.balance are different memory locations.
Declared with static. ONE copy shared by ALL instances. Perfect for counters like totalAccounts that track the whole system.
private? If balance were public, any code could do alice.balance = -99999 β bypassing all validation. Making it private forces everyone to use your controlled setter methods.// Getter β read-only access to private field
public double getBalance() {
return balance;
}
// Getter for name
public String getName() {
return name;
}
// Static getter β accessed on CLASS, not instance
public static int getTotalAccounts() {
return totalAccounts;
}
A constructor is a special method called when you use new. It has the same name as the class and no return type. Its job: set up the initial state of a new object.
public class BankUser {
private String name;
private String accountId;
private double balance;
private boolean isActive;
private static int totalAccounts = 0;
// ββ CONSTRUCTOR ββββββββββββββββββββββββββββββββββββ
// Same name as class, no return type
public BankUser(String name, String accountId, double initialBalance) {
// 'this' refers to the current instance being created
this.name = name;
this.accountId = accountId;
// Validate: balance can't start negative
if (initialBalance < 0) {
throw new IllegalArgumentException("Balance can't be negative");
}
this.balance = initialBalance;
this.isActive = true; // new accounts start active
totalAccounts++; // update class-level counter
System.out.println("β
Account created for: " + name);
}
// Overloaded constructor β start with $0 balance
public BankUser(String name, String accountId) {
this(name, accountId, 0.0); // delegates to main constructor
}
}
this keyword β refers to the current instance. Used to distinguish between the constructor parameter name and the field this.name. Without it, the assignment would do nothing useful.this(...) calls another constructor in the same class, avoiding code duplication.// Full constructor
BankUser alice = new BankUser("Alice", "ACC001", 5000.0);
// prints: β
Account created for: Alice
// Overloaded constructor (zero balance)
BankUser charlie = new BankUser("Charlie", "ACC003");
// prints: β
Account created for: Charlie
System.out.println(BankUser.getTotalAccounts()); // 2
Methods define what an object can do. They can read/modify fields, take parameters, and return values. Access modifier (public/private) + return type + name + parameters.
| Method | Access | Returns | Purpose |
|---|---|---|---|
deposit(double amount) |
public | void | Adds money to balance |
withdraw(double amount) |
public | boolean | Removes money; returns success |
transfer(BankUser, double) |
public | boolean | Move money to another user |
getBalance() |
public | double | Read-only balance access |
printStatement() |
public | void | Print account summary |
validateAmount(double) |
private | boolean | Internal validation helper |
// ββ DEPOSIT ββββββββββββββββββββββββββββββββββββββββ
// void = returns nothing. Just changes state.
public void deposit(double amount) {
if (!validateAmount(amount)) {
System.out.println("β Invalid deposit amount");
return;
}
balance += amount; // modifies THIS instance's field
System.out.printf("β
Deposited $%.2f β Balance: $%.2f%n", amount, balance);
}
// ββ WITHDRAW βββββββββββββββββββββββββββββββββββββββ
// boolean return: true = success, false = failed
public boolean withdraw(double amount) {
if (!validateAmount(amount)) {
System.out.println("β Invalid amount");
return false;
}
if (amount > balance) {
System.out.println("β Insufficient funds");
return false;
}
balance -= amount;
System.out.printf("β
Withdrew $%.2f β Balance: $%.2f%n", amount, balance);
return true;
}
// ββ PRIVATE HELPER βββββββββββββββββββββββββββββββββ
// private: only usable inside BankUser class
private boolean validateAmount(double amount) {
return amount > 0 && isActive;
}
The transfer() method is the most interesting β it takes another BankUser object as a parameter. This shows how objects can interact with each other in Java.
// ββ TRANSFER βββββββββββββββββββββββββββββββββββββββ
// Takes ANOTHER BankUser object as a parameter
public boolean transfer(BankUser recipient, double amount) {
// Step 1: try to withdraw from THIS user
boolean success = this.withdraw(amount);
if (!success) {
System.out.println("β Transfer failed: check your balance");
return false;
}
// Step 2: deposit into recipient object
recipient.deposit(amount);
System.out.printf(
"π Transferred $%.2f from %s β %s%n",
amount, this.name, recipient.getName()
);
return true;
}
recipient is a reference to another BankUser object. Inside the method, calling recipient.deposit() modifies THAT object's balance. this = the sender. recipient = the receiver.BankUser alice = new BankUser("Alice", "ACC001", 5000.0);
BankUser bob = new BankUser("Bob", "ACC002", 1200.0);
System.out.println("Before:");
alice.printStatement(); // Alice: $5000.00
bob.printStatement(); // Bob: $1200.00
// Alice sends $800 to Bob
alice.transfer(bob, 800.0);
System.out.println("After:");
alice.printStatement(); // Alice: $4200.00
bob.printStatement(); // Bob: $2000.00
// Try over-limit transfer
alice.transfer(bob, 99999.0);
// β Transfer failed: check your balance
public void printStatement() {
System.out.println("βββββββββββββββββββββββββ");
System.out.println("Account: " + accountId);
System.out.println("Holder: " + name);
System.out.printf( "Balance: $%.2f%n", balance);
System.out.println("Status: " + (isActive ? "Active" : "Closed"));
System.out.println("βββββββββββββββββββββββββ");
}
The full BankUser.java and Main.java β everything assembled, ready to copy and run.
public class BankUser {
// ββ FIELDS βββββββββββββββββββββββββββββββββββββββββ
private String name;
private String accountId;
private double balance;
private boolean isActive;
private static int totalAccounts = 0; // class-level
// ββ CONSTRUCTORS ββββββββββββββββββββββββββββββββββββ
public BankUser(String name, String accountId, double initialBalance) {
if (initialBalance < 0) throw new IllegalArgumentException("Negative balance");
this.name = name;
this.accountId = accountId;
this.balance = initialBalance;
this.isActive = true;
totalAccounts++;
System.out.println("β
Account created for: " + name);
}
public BankUser(String name, String accountId) {
this(name, accountId, 0.0); // delegate
}
// ββ METHODS βββββββββββββββββββββββββββββββββββββββββ
public void deposit(double amount) {
if (!validateAmount(amount)) { System.out.println("β Invalid deposit"); return; }
balance += amount;
System.out.printf("β
Deposited $%.2f | New balance: $%.2f%n", amount, balance);
}
public boolean withdraw(double amount) {
if (!validateAmount(amount)) { System.out.println("β Invalid amount"); return false; }
if (amount > balance) { System.out.println("β Insufficient funds"); return false; }
balance -= amount;
System.out.printf("β
Withdrew $%.2f | New balance: $%.2f%n", amount, balance);
return true;
}
public boolean transfer(BankUser recipient, double amount) {
if (!this.withdraw(amount)) {
System.out.println("β Transfer failed"); return false;
}
recipient.deposit(amount);
System.out.printf("π Transferred $%.2f: %s β %s%n", amount, name, recipient.getName());
return true;
}
public void printStatement() {
System.out.println("βββββββββββββββββββββββββ");
System.out.println("Account: " + accountId);
System.out.println("Holder: " + name);
System.out.printf( "Balance: $%.2f%n", balance);
System.out.println("Status: " + (isActive ? "Active" : "Closed"));
System.out.println("βββββββββββββββββββββββββ");
}
// ββ GETTERS βββββββββββββββββββββββββββββββββββββββββ
public String getName() { return name; }
public String getAccountId() { return accountId; }
public double getBalance() { return balance; }
public boolean isActive() { return isActive; }
public static int getTotalAccounts() { return totalAccounts; }
// ββ PRIVATE HELPER ββββββββββββββββββββββββββββββββββ
private boolean validateAmount(double amount) {
return amount > 0 && isActive;
}
}
public class Main {
public static void main(String[] args) {
// Create two users
BankUser alice = new BankUser("Alice", "ACC001", 5000.0);
BankUser bob = new BankUser("Bob", "ACC002", 1200.0);
// Check class-level counter
System.out.println("Total accounts: " + BankUser.getTotalAccounts()); // 2
// Deposit & withdraw
alice.deposit(500.0);
bob.withdraw(200.0);
// Transfer
alice.transfer(bob, 800.0);
// Print statements
alice.printStatement();
bob.printStatement();
// Try a bad transfer
alice.transfer(bob, 999999.0); // β Insufficient funds
}
}