CyberStars

Getters and Setters

So far, we've been accessing fields directly: player.name, player.score. That works, but it's like leaving your front door wide open. Anyone can walk in and change anything

In real Java code, we hide fields and control access through methods. This concept is called encapsulation


The Problem with Public Fields

class BankAccount {
    int balance;

    BankAccount(int balance) {
        this.balance = balance;
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount acc = new BankAccount(1000);
        acc.balance = -999999;  // Uh oh. Nobody stopped us
        System.out.println(acc.balance);
    }
}

Output

-999999

Phil Cassidy could just waltz in and set his bank balance to whatever he wants. That's bad. We need a bouncer at the door


Private Fields + Getters and Setters

The private keyword means "only code inside this class can touch this field":

class BankAccount {
    private int balance;

    BankAccount(int balance) {
        this.balance = balance;
    }

    int getBalance() {
        return balance;
    }

    void deposit(int amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    void withdraw(int amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount acc = new BankAccount(1000);
        acc.deposit(500);
        acc.withdraw(200);
        // acc.balance = -999999;  // ERROR! balance is private
        System.out.println("Balance: " + acc.getBalance());
    }
}

Output

Balance: 1300

Now the only way to change the balance is through deposit() and withdraw(), which have validation built in. Negative deposits? Ignored. Withdrawing more than you have? Nope


Getter and Setter Pattern

The standard Java pattern:

  • Getter: a method that returns a private field's value. Named getFieldName()
  • Setter: a method that sets a private field's value (with validation). Named setFieldName()
class Player {
    private String name;
    private int health;

    Player(String name, int health) {
        this.name = name;
        this.health = health;
    }

    String getName() {
        return name;
    }

    int getHealth() {
        return health;
    }

    void setHealth(int health) {
        if (health >= 0 && health <= 100) {
            this.health = health;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Player p = new Player("Tommy Vercetti", 100);
        p.setHealth(75);
        System.out.println(p.getName() + ": " + p.getHealth() + " HP");
        p.setHealth(-50);  // Ignored! Invalid value
        System.out.println(p.getName() + ": " + p.getHealth() + " HP");
    }
}

Output

Tommy Vercetti: 75 HP
Tommy Vercetti: 75 HP

The setHealth(-50) call was silently ignored because our setter rejects negative values. That's the power of encapsulation: you control the rules


When to Skip Setters

Not every field needs a setter. Sometimes a field should be set once (in the constructor) and never changed. If name shouldn't change after creation, just don't write setName(), problem solved

The getter still lets people read the name, but nobody can change it. This is a common and good pattern


Mission: Tommy's Account

Tommy keeps his money at the bank and wants a secure transaction system. He can deposit and withdraw money, but the account must reject invalid operations: no negative deposits and no withdrawing more than he has.

Create a BankAccount class with:

  1. A private int balance field
  2. A constructor that takes the starting balance
  3. A getBalance() method that returns the balance
  4. A deposit(int amount) method that adds to balance (only if amount > 0)
  5. A withdraw(int amount) method that subtracts from balance (only if amount > 0 and amount <= balance)

In main, store the values in variables: start for the starting balance, deposit for the amount you deposit, withdraw1 and withdraw2 for the two withdrawals. Then create an account with start, deposit deposit, withdraw withdraw1, then try to withdraw withdraw2 (should fail silently when it's more than the balance) and print the final balance.

Example: account started at 1000, +500, -200, then -2000 rejected

1300