Encapsulating Data
OCP Exam Topic — Apply encapsulation using private fields, public getters/setters, and JavaBeans naming conventions. Covered in Chapter 5 of OCP Java SE 21 Developer Study Guide (Selikoff & Boyarsky).
What Is Encapsulation?
Encapsulation bundles data (fields) and the code that operates on that data (methods) into a single unit, while restricting direct access to the data from outside the class. The goal is to hide internal state and require all interactions to go through a controlled interface.
The standard Java pattern for encapsulation:
- Declare fields
private. - Provide
publicgetter and setter methods to read and write those fields.
Private Fields and Public Accessors
javapublic class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
this.age = age;
}
}The setter for age validates the input before applying it — something impossible when the field is public and written to directly.
JavaBeans Naming Conventions
The JavaBeans specification defines naming rules that many frameworks (Spring, JPA, Hibernate, CDI) rely on to discover getters and setters via reflection.
| Member Type | Convention | Example |
|---|---|---|
| Getter for non-boolean | get + capitalized field name |
getName() |
| Getter for boolean | is + capitalized field name |
isActive() |
| Setter | set + capitalized field name |
setName(String name) |
javapublic class Account {
private String owner;
private boolean active;
private double balance;
// getters
public String getOwner() { return owner; }
public boolean isActive() { return active; } // "is" prefix for boolean
public double getBalance() { return balance; }
// setters
public void setOwner(String owner) { this.owner = owner; }
public void setActive(boolean active) { this.active = active; }
public void setBalance(double balance) { this.balance = balance; }
}Exam note: A boolean getter named getActive() is valid Java but does not follow the JavaBeans convention. The OCP exam tests whether you recognize the is prefix for boolean getters.
Benefits of Encapsulation
Validation — Setters can enforce business rules before changing state:
javapublic void setBalance(double balance) {
if (balance < 0) throw new IllegalArgumentException("Balance cannot be negative");
this.balance = balance;
}Read-only fields — Omit the setter to make a field read-only from outside the class:
javapublic class ImmutablePoint {
private final int x;
private final int y;
public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
// no setX / setY — callers cannot modify x or y
}Flexibility to change internals — You can change how data is stored without breaking callers, because they only depend on the method signatures, not the field names.
Immutable Classes Pattern
An immutable class has no setters, declares all fields final, and ensures that mutable objects referenced by its fields cannot be modified externally. Java's own String and LocalDate follow this pattern.
javapublic final class Money {
private final int cents;
public Money(int cents) {
if (cents < 0) throw new IllegalArgumentException("Cannot be negative");
this.cents = cents;
}
public int getCents() { return cents; }
public Money add(Money other) {
return new Money(this.cents + other.cents); // returns new instance
}
@Override
public String toString() {
return "$" + cents / 100 + "." + String.format("%02d", cents % 100);
}
}
Money price = new Money(999);
Money taxed = price.add(new Money(80));
System.out.println(taxed); // $10.79Rules for building an immutable class:
- Declare the class
final(prevents subclasses from breaking immutability). - Declare all fields
private final. - Initialize all fields in the constructor.
- Provide no setters.
- Return copies of mutable fields from getters (defensive copying).
Common Mistakes
java// Mistake 1 — wrong prefix for boolean getter
public boolean getEnabled() { return enabled; } // valid Java but not JavaBeans-compliant
// Mistake 2 — setter returns a value (violates JavaBeans convention)
public int setAge(int age) { this.age = age; return age; } // setter must return void
// Mistake 3 — public field (breaks encapsulation)
public String name; // any class can read or write name without validationKey Points to Remember
- Declare fields
privateand expose them throughpublicgetter/setter methods. - Follow JavaBeans naming:
getX()for non-boolean,isX()for boolean,setX(value)for mutators. - Setters must return
void; getters must return the field type. - Omitting a setter makes the property effectively read-only to external callers.
- Immutable classes combine
private finalfields, constructor initialization, no setters, and afinalclass declaration. - Encapsulation allows validation, controlled change, and the freedom to refactor internals without breaking the public API.