Encapsulation & access modifiers
private, package-private, protected and public; getters, setters, validation and immutable classes.
In the classes lesson, anyone could write account.balance = -1_000_000; and break our bank. Encapsulation means hiding an object's internal data and allowing access only through carefully designed methods. The class stays in control of its own state, so it can guarantee the data is always valid.
Access modifiers#
Java has four access levels, from most to least restrictive:
They can be applied to fields, methods, constructors and nested classes. Top-level classes can only be public or package-private.
A good default:
- Fields:
private, almost always. - Methods:
publicif they are part of the class's API,privateif they are internal helpers. - Constructors: usually
public;privatefor utility classes, singletons and static factories. protected: for members that subclasses need. Use with care, as it widens access to the whole package too.
Encapsulating a bank account#
What we gained:
- Valid state is guaranteed. The balance can only change through
depositandwithdraw, which enforce the rules. - Read-only where it should be.
numberandownerhave getters but no setters. - Freedom to change internals. We could store the balance as
longpaise tomorrow; as long asgetBalance()behaves the same, no caller breaks.
Getters and setters#
The conventional names are getX() / setX(value), and isX() for booleans:
Do not generate a getter and setter for every field by reflex. That is just a public field with extra steps. Ask: should outsiders really change this? Often a meaningful method (
deactivate(),applyDiscount(10)) is a better API than a raw setter.
Many frameworks (Spring, Hibernate, Jackson) recognise the getX/setX/isX naming convention, so following it matters in practice.
Tell, don't ask#
Encapsulation is not just about private. It is about putting behaviour next to the data it uses. Compare:
In the second version, the rule "you cannot overdraw" lives in exactly one place.
Immutable classes#
The strongest form of encapsulation is an immutable object whose state can never change after construction. String, Integer and LocalDate are immutable. To make your own:
- Make all fields
private final. - Provide no setters.
- Make the class
final(so subclasses cannot add mutable behaviour). - Return new objects from "modifying" methods.
- Make defensive copies of mutable inputs and outputs (arrays, lists, dates from old APIs).
Immutable objects are simple to reason about, safe to share between threads, and make excellent HashMap keys. For pure data classes, Java's records (a later lesson) give you this almost for free.
Package-private in practice#
Leaving off a modifier means "visible to my package". It is useful for helpers that several classes in the same package collaborate on but that should not be part of the public API:
Code outside com.elephantoo.billing cannot even see TaxCalculator, so you can rewrite it freely. You will learn how packages work in the packages lesson.
Why protected should be rare#
protected fields couple subclasses to the parent's internals. Prefer private fields with protected (or public) methods. You will see this in the inheritance lesson.
A checklist for well-encapsulated classes#
- All fields
private(andfinalwhere possible). - Constructors establish a valid state and reject invalid input.
- Every public method keeps the object valid.
- No mutable internals leak out (return copies or unmodifiable views).
- Internal helpers are
private. - The public API describes behaviour, not just raw data access.
Common mistakes#
- Public fields "for convenience", which lose all control over the data.
- Setters with no validation, which put the same problem behind a method.
- Returning internal mutable collections or arrays directly.
- Exposing implementation details as
public, because once others depend on them, you can never change them.
What's next#
With encapsulated building blocks in hand, we can start building class hierarchies. Next up: inheritance with extends and super.
Check your understanding
Quick quiz
1.Which access modifier allows access only from inside the same class?
2.A field has no access modifier at all. Who can access it?
3.A class has
private final List<String> tags;andpublic List<String> getTags() { return tags; }. What is the problem?
Finished reading?
Mark this lesson complete to track your progress.