Java - Encapsulation
Encapsulation
Access Modifiers
- public: visible everywhere
- protected: visible in same package and subclasses
- (package-private): no modifier; visible in same package
- private: visible only within the declaring class
Getters/Setters with Validation
public class BankAccount {
  private int balance; // cents
  public synchronized void deposit(int cents) {
    if (cents <= 0) throw new IllegalArgumentException("positive only");
    balance += cents;
  }
  public synchronized int getBalance() { return balance; }
}
Immutability
Make state unchangeable after construction to simplify reasoning and enable thread-safety.
public final class Address {
  private final String city;
  private final java.util.List lines;
  public Address(String city, java.util.List lines) {
    this.city = city;
    this.lines = java.util.List.copyOf(lines); // defensive copy
  }
  public String getCity() { return city; }
  public java.util.List getLines() { return lines; } // unmodifiable
}
   Defensive Copies
Never expose internal mutable state directly.
class User {
  private final java.util.Date registeredAt;
  User(java.util.Date d) { this.registeredAt = new java.util.Date(d.getTime()); }
  public java.util.Date getRegisteredAt() { return new java.util.Date(registeredAt.getTime()); }
}
Avoid public mutable fields. Expose behavior, not representation. Keep invariants enforced at the boundaries.
  Try it
- Expose an internal Listsafely by returningList.copyOfinstead of the mutable list.
- Add validation to a setter and test that invalid values throw exceptions.