Encapsulation
How encapsulation protects object state, enforces invariants, and makes code maintainable — the OOP principle every senior developer relies on.
Last reviewed: January 2025
🔍 What Is It?
Encapsulation is one of the four pillars of OOP. It means:
1. Data Hiding
Fields are declared private — they cannot be accessed directly from outside the class.
2. Controlled Access
Public getter and setter methods provide controlled read/write access.
3. Invariant Enforcement
Setters validate data before accepting it, ensuring the object is always in a valid state.
4. Implementation Independence
Internal representation can change without affecting callers — only the public interface matters.
Access Modifiers:
- →
private— accessible only within the same class - →
package-private(no modifier) — accessible within the same package - →
protected— accessible within same package + subclasses - →
public— accessible from anywhere
🎯 Why Do We Need It?
Without encapsulation:
// BAD: public fields, no protection
class BankAccount {
public double balance; // anyone can set balance = -999999
}
account.balance = -1000000; // silently broken!With encapsulation:
// GOOD: private field, controlled access
class BankAccount {
private double balance;
public void deposit(double amount) {
if (amount <= 0) throw new IllegalArgumentException("Amount must be positive");
this.balance += amount;
}
}Encapsulation enforces business rules at the object level, making it impossible to put an object in an invalid state.
🏗️ What Happens in Real Projects?
In enterprise projects, encapsulation appears everywhere:
- →JPA Entities — private fields with getters; setters only where needed
- →Validation — setters throw IllegalArgumentException for invalid data
- →Immutable Value Objects — no setters at all; state set only in constructor
- →Builder Pattern — encapsulates complex construction logic
- →Service Layer — business rules encapsulated in service methods, not exposed directly
⚙️ How It Works
Getter/Setter Convention:
- →Getter:
public Type getFieldName()(orisFieldName()for boolean) - →Setter:
public void setFieldName(Type value)
Lombok reduces boilerplate:
@Getter @Setter
@NoArgsConstructor @AllArgsConstructor
public class Employee { ... }Immutability is the strongest form of encapsulation:
No setters + final fields = object cannot change after construction = thread-safe by default.
💻 Example
Encapsulation in a Banking Domain — A BankAccount class showing how encapsulation enforces business rules.
🤔 Common Confusions
❓ If I have getters and setters for every field, am I really encapsulating?
Not really. A class with public getters and setters for every field is barely better than public fields — it is "anemic encapsulation." True encapsulation means only exposing what callers need, and enforcing invariants in setters. Ask: does every field need a setter? Can some operations be expressed as business methods (deposit, withdraw) instead of raw setters?
❓ What is the difference between encapsulation and information hiding?
They are closely related but not identical. Encapsulation is the mechanism (private fields + public methods). Information hiding is the principle (callers should not need to know implementation details). Encapsulation is how you achieve information hiding in Java.
❓ Should I always use getters/setters or can fields ever be public?
There are valid cases for public fields: records (Java 16+, though they use accessors), simple data holders in test code, and mathematical types like Point where x and y are inherently public. In production business code, keep fields private. The Java community convention is clear: private fields with accessors.
🚨 Common Production Issues
Returning mutable collections from getters — if getList() returns the internal list, callers can modify it. Return Collections.unmodifiableList() or a copy.
Setters that bypass validation — adding a setter to fix a compilation error without thinking about invariants breaks encapsulation silently.
Anemic domain model — entities with only getters/setters and no business logic. Business rules end up scattered in service classes, making the domain model meaningless.
✅ Best Practices
Make all fields private by default. Add getters only when needed, setters only when mutation is required.
Return defensive copies or unmodifiable views of mutable collections from getters.
Prefer immutability — no setters, final fields, records. Immutable objects are thread-safe by default.
Express business operations as methods (deposit, activate, cancel) rather than raw setters.
Use Lombok @Value or records for immutable data classes to reduce boilerplate.
🏛️ Architect's Note
The debate between rich domain models (business logic in entities) and anemic domain models (logic in services) is ongoing. Rich models follow true encapsulation — the Order class knows how to add items, calculate totals, and validate itself. Anemic models put all logic in OrderService. For complex domains, rich models are more maintainable. For simple CRUD apps, anemic models are fine. Choose based on domain complexity.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
Core Java Interview Prep
Practice interview questions that connect directly to this technology track.
↗ Where this topic fits
Core Java Technology Guide
Return to the Core Java learning hub.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Core Java references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Core Java learning path
Browse the full Core Java topic collection and learning order on SplashRide.
Core Java Interview Prep
Practice Core Java interview questions and scenario-based answers.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Classes & Objects
The foundation of Java OOP — how classes define blueprints and objects are instances, with constructors, fields, methods, and the this keyword.
Inheritance
How Java inheritance works — extends, super, method overriding, and when to use inheritance vs composition in real enterprise projects.