Encapsulation
Encapsulation means bundling an object's data (fields) and the methods that operate on that data together into a single unit — a class — while restricting direct access to the internal state from outside code. Instead of letting other code reach in and change a field freely, the class controls access through its own methods.
The classic pattern: private fields, public accessors
The most common way to encapsulate a class in Java is to make its fields private and expose controlled access through public getter and setter methods.
A minimally-encapsulated class
public 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) {
this.age = age;
}
}On its own, this looks like it just adds boilerplate around plain field access — and it would, if the setters did nothing more than assign the value. The real payoff of encapsulation shows up once a setter actually enforces a rule.
Why it matters: protecting invariants
An invariant is a rule about an object's state that should always hold true — for example, “a person's age can never be negative.” If fields were public, any code anywhere could set person.age = -5 and nothing would stop it. By keeping the field private and forcing every change through a setter, the class gets one chokepoint where it can validate input and refuse to let the object enter an invalid state.
Validating input in a setter
public class Person {
private String name;
private int age;
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative: " + age);
}
this.age = age;
}
public int getAge() {
return age;
}
}
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.setAge(30); // fine
p.setAge(-5); // throws IllegalArgumentException — invariant protected
}
}Because age is private, this validation logic is the only way to change it — there is no back door. That guarantee is what encapsulation buys you: every Person object that exists is guaranteed to have never had a negative age, at any point in its lifetime.
Not just getters and setters
Encapsulation is a broader idea than “always write a getter and setter for every field.” Sometimes the right amount of encapsulation is no setter at all — for example, an immutable class might expose only a getter and set the field once, in the constructor, exactly like the final fields you'll see on Records. The core principle is the same either way: the class, not outside code, decides how its own state can change.
Encapsulation bundles data and behavior into one class and restricts direct access to the data.
The classic pattern:
privatefields,publicgetter/setter methods.Setters are the natural place to validate input and protect an object's invariants.
Exposing a mutable field or returning a mutable internal reference silently defeats encapsulation.