Java Encapsulation
Access Modifiers
Encapsulation bundles data (fields) and methods together and restricts direct access to internal state. Java provides four access modifiers to control visibility.
| Modifier | Same Class | Same Package | Subclass | Everywhere |
|---|---|---|---|---|
private | Yes | No | No | No |
default (no keyword) | Yes | Yes | No | No |
protected | Yes | Yes | Yes | No |
public | Yes | Yes | Yes | Yes |
Getters, Setters & JavaBeans
The standard pattern is to declare fields private and expose them through public getter and setter methods. This is the JavaBeans convention.
public class BankAccount { // private fields - hidden from outside private String owner; private double balance; public BankAccount(String owner, double initialBalance) { this.owner = owner; this.balance = (initialBalance >= 0) ? initialBalance : 0; } // Getter public String getOwner() { return owner; } // Getter with read-only access public double getBalance() { return balance; } // Controlled mutation - validation inside setter public void deposit(double amount) { if (amount > 0) { balance += amount; System.out.printf("Deposited $%.2f. New balance: $%.2f%n", amount, balance); } else { System.out.println("Deposit amount must be positive."); } } public void withdraw(double amount) { if (amount > 0 && amount <= balance) { balance -= amount; System.out.printf("Withdrew $%.2f. New balance: $%.2f%n", amount, balance); } else { System.out.println("Invalid withdrawal amount."); } } public static void main(String[] args) { BankAccount acc = new BankAccount("Alice", 1000.0); System.out.println("Owner: " + acc.getOwner()); acc.deposit(500.0); acc.withdraw(200.0); acc.withdraw(2000.0); // Invalid // acc.balance = 999999; // ERROR: balance is private }} JavaBeans Convention
A JavaBean is a class that follows these rules:
import java.io.Serializable;public class Student implements Serializable { private String name; private int age; private double gpa; private boolean enrolled; // No-arg constructor (required for JavaBean) public Student() {} // Getters public String getName() { return name; } public int getAge() { return age; } public double getGpa() { return gpa; } public boolean isEnrolled() { return enrolled; } // boolean uses 'is' // Setters with validation public void setName(String name) { this.name = name; } public void setAge(int age) { if (age > 0) this.age = age; } public void setGpa(double gpa) { if (gpa >= 0 && gpa <= 4.0) this.gpa = gpa; } public void setEnrolled(boolean e) { this.enrolled = e; } @Override public String toString() { return String.format("Student{name='%s', age=%d, gpa=%.2f, enrolled=%b}", name, age, gpa, enrolled); } public static void main(String[] args) { Student s = new Student(); s.setName("Bob"); s.setAge(20); s.setGpa(3.75); s.setEnrolled(true); System.out.println(s); }}
Key Takeaways
- Encapsulation hides internal state and requires all interaction through methods.
- Use private fields with public getters and setters to control access.
- Setters can validate input before storing - this protects data integrity.
- Immutable classes (all fields final, no setters) are inherently thread-safe.
- Java records (Java 16+) automatically generate getters, equals, hashCode, and toString.
- Encapsulation is one of the four pillars of OOP alongside Inheritance, Polymorphism, and Abstraction.
Related Java Topics