Java OOP Encapsulation
Protecting the Object
Story: Our application is growing. We have created objects, but now we discover a problem: anyone can directly change their internal data. We need to teach objects how to protect themselves.
1. The Problem
Consider:
class BankAccount {
double balance;
}Now outside code can do:
BankAccount account = new BankAccount();
account.balance = -500000;Our object is now in an invalid state.
The question becomes:
How do we stop outside code from directly manipulating internal state?
The answer begins with encapsulation.
2. private
We can make the field private:
class BankAccount {
private double balance;
}Now outside code cannot directly access:
account.balance;The field can only be directly accessed from inside BankAccount.
3. What Is Encapsulation?
Encapsulation means:
Controlling access to an object’s internal state and behavior so that the object can protect its own rules and invariants.
It is more than simply:
“Make fields private.”
A better mental model is:
Internal State
↓
Protected
↓
Controlled Public API
↓
Valid Object State4. Public API
Instead of allowing:
account.balance = 1000;We expose a meaningful operation:
account.deposit(1000);Example:
class BankAccount {
private double balance;
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException(
"Amount must be positive"
);
}
balance += amount;
}
}Now the object controls how its state changes.
5. Invariants
An invariant is a condition that should remain true for an object.
Examples:
BankAccount
balance >= 0
Student
0 <= marks <= 100
Employee
salary > 0Encapsulation allows the class to protect these rules.
6. Getters
A getter allows controlled access to a value.
class Person {
private String name;
public String getName() {
return name;
}
}Usage:
Person p = new Person();
System.out.println(p.getName());7. Setters
A setter allows controlled modification.
public void setName(String name) {
this.name = name;
}However, don’t automatically create setters for every field.
A setter is appropriate only when outside code should actually be allowed to change the value.
8. Getter Without Setter
Some values should be readable but not changeable.
Example:
class Employee {
private final int employeeId;
Employee(int employeeId) {
this.employeeId = employeeId;
}
public int getEmployeeId() {
return employeeId;
}
}There is:
getEmployeeId()but no:
setEmployeeId()The ID is initialized once and then remains unchanged.
9. Behavior Is Often Better Than Setters
Consider:
account.setBalance(
account.getBalance() + 1000
);This exposes too much of the object’s internal state.
Prefer:
account.deposit(1000);Why?
Because deposit() represents a meaningful operation.
The object owns the logic:
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException();
}
balance += amount;
}The outside world says:
“Deposit 1000.”
The object decides:
“How should that happen?”
10. Tell, Don’t Ask
Compare:
account.setBalance(
account.getBalance() + amount
);with:
account.deposit(amount);The second is more object-oriented.
Get Amit Kumar’s stories in your inbox
Join Medium for free to get updates from this writer.
Instead of asking the object for its internal state and manipulating it externally, we tell the object what operation we want.
Mental Model
Bad
Object → give me your data
Outside → I'll manipulate itBetter
Outside → perform this operation
Object → I'll handle the rules11. Access Modifiers
Java has four important access levels.
private
Accessible directly only within the declaring class.
private
↓
declaring classPackage-private
No modifier is specified.
String name;Accessible within the same package.
protected
Accessible within the same package and through subclass access according to Java’s protected-access rules.
public
Broadly accessible.
12. Access Modifier Mental Model
private
↓
Only declaring class
package-private
↓
Same package
protected
↓
Same package + subclass access
public
↓
Broad accessThe exact protected rules become more important when studying inheritance.
13. Encapsulation Is Not Just Private Fields
This is a common misconception:
“If I make the field private, I have achieved perfect encapsulation.”
Not necessarily.
Consider:
class BankAccount {
private double balance;
public void setBalance(double balance) {
this.balance = balance;
}
}The field is private, but this is still possible:
account.setBalance(-500000);The public API has allowed an invalid state.
Good encapsulation means:
Private state
+
Controlled operations
+
Validation
+
Protected invariants14. Encapsulation vs Abstraction
These concepts are related but different.
Encapsulation
Focus:
Protect and control internal state.
Typical tools:
private
public
protected
methodsAbstraction
Focus:
Hide unnecessary complexity and expose essential concepts.
Typical tools:
abstract class
interfaceEasy Memory Trick
Encapsulation protects the inside.
Abstraction simplifies the outside.
15. Immutability
An immutable object is an object whose observable state cannot be changed after construction.
Example:
final class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}There are:
private fields
+
final fields
+
no settersOnce the object is created, its state cannot be changed through its API.
16. final Does Not Automatically Mean Immutable
Consider:
final List<String> names = new ArrayList<>();This is not necessarily immutable.
You cannot do:
names = new ArrayList<>();But you can still do:
names.add("Amit");Why?
Because:
final reference
↓
cannot point to another objectreferenced object
↓
can still be mutableRemember
finalreference ≠ immutable object.
17. Constructor + Encapsulation
Constructors and encapsulation work together.
class Employee {
private final int id;
Employee(int id) {
if (id <= 0) {
throw new IllegalArgumentException();
}
this.id = id;
}
}The constructor establishes a valid initial state.
Then private state prevents uncontrolled modification.
Constructor
↓
Valid initial state
private
↓
Protect state
Methods
↓
Control future changes18. Encapsulation in a Real Class
class BankAccount {
private final String accountNumber;
private double balance;
public BankAccount(String accountNumber) {
this.accountNumber = accountNumber;
this.balance = 0;
}
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException();
}
balance += amount;
}
public void withdraw(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException();
}
if (amount > balance) {
throw new IllegalArgumentException(
"Insufficient balance"
);
}
balance -= amount;
}
public double getBalance() {
return balance;
}
public String getAccountNumber() {
return accountNumber;
}
}Outside code cannot directly manipulate:
balance
accountNumberInstead it uses meaningful operations.
19. Core Mental Model
Think of an object as a small protected system:
OBJECT
┌─────────────────┐
│ │
Outside │ private state │
────► │ │
│ public methods │
│ │
└─────────────────┘
│
↓
Controlled stateThe object should own the rules for its own state.
Quick Revision
Encapsulation
Control access to internal state and protect object invariants.
private
Directly accessible only inside the declaring class.
Getter
Controlled way to read state.
Setter
Controlled way to modify state.
Invariant
Condition that should remain valid for an object.
Immutability
Object state cannot change after construction.
final
Prevents reassignment of a variable/reference; it does not automatically make referenced objects immutable.
Good encapsulation
Private state + meaningful public behavior + validation.









