6 · 32 · 5 min
Encapsulation, and the getter that leaks
Encapsulation is hiding how something works so it can be changed without breaking anyone.
class Account {
private double balance;
public double getBalance() { return balance; }
public void deposit(double amount) {
if (amount <= 0) throw new IllegalArgumentException("must be positive");
balance += amount;
}
}balance is private, so nothing outside can set it directly, and the deposit rule cannot be bypassed. Change the internal representation to paise stored as a long, and no caller notices.
The leak
class Student {
private List<String> courses = new ArrayList<>();
public List<String> getCourses() { return courses; }
}
student.getCourses().add("hacked"); // this worksThe field is private and there is no setter. It still worked.
private stops you reassigning the field. It says nothing about the object the field points at, and the getter handed out a reference to it. The caller is now mutating the student's own list.
Two fixes:
return new ArrayList<>(courses); // a copy
return Collections.unmodifiableList(courses); // a read-only viewWhy it matters more than it looks
Encapsulation is what makes a class changeable. A field nobody outside can touch can be renamed, retyped or removed this afternoon. A field everyone reaches into is frozen forever.