Writing Classes
Design classes with instance variables, constructors, accessor methods, mutator methods, helper methods, and encapsulation.
A lesson of AP Computer Science A, in Objects and Classes, about 10 minutes.
By the end of this lesson, you will be able to design and implement a complete Java class with fields, constructors, accessors, mutators, and toString.
Class Design Checklist
A well-designed class has:
- Private instance variables (fields) for the object's state
- One or more constructors
- Public getter methods (accessors)
- Public setter methods (mutators) where appropriate
- Override of
toString()for meaningful output - Override of
equals()for content comparison (optional but good practice)
Complete Example: BankAccount
public class BankAccount {
// 1. Private fields
private String owner;
private double balance;
private int accountNumber;
private static int nextAccountNumber = 1001; // shared counter
// 2. Constructor
public BankAccount(String owner, double initialDeposit) {
this.owner = owner;
this.balance = initialDeposit;
this.accountNumber = nextAccountNumber;
nextAccountNumber++;
}
// 3. Accessors (getters)
public String getOwner() { return owner; }
public double getBalance() { return balance; }
public int getAccountNumber() { return accountNumber; }
// 4. Mutators (setters and other modifiers)
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true; // success
}
return false; // failed (insufficient funds or invalid amount)
}
// 5. toString
public String toString() {
return "Account #" + accountNumber + " (" + owner + "): $" + balance;
}
}
Using the Class
BankAccount alice = new BankAccount("Alice", 1000.0);
BankAccount bob = new BankAccount("Bob", 500.0);
alice.deposit(250.0);
boolean success = alice.withdraw(200.0);
System.out.println(alice); // calls toString automatically
// → Account #1001 (Alice): $1050.0
System.out.println(BankAccount.nextAccountNumber); // ERROR! nextAccountNumber is private
Design Decisions
Why private fields? Protects integrity — prevents code outside the class from setting balance to -$1,000,000. All changes go through methods that can validate.
Why validate in setters? The withdraw method returns false if there aren't sufficient funds, instead of allowing a negative balance. The class enforces its own invariants.
Why static nextAccountNumber? Every account needs a unique number; the counter is shared across ALL instances of the class, not per-object.