Skip to main content

Encapsulation βœ”

Encapsulation is one of the core principles of object-oriented programming (OOP). It means:

Bundling data and behavior together, and controlling access to internal state so the object protects its own consistency.

danger

Encapsulation has two key aspects:

  1. Information Hiding
  2. Maintaining Invariants

Information Hiding​

danger

Information hiding means:

  • The internal representation (data structures, variables) of a class is not directly accessible from outside.
  • External code interacts only through a well-defined public interface (methods).

The goal:

  • Prevent misuse
  • Reduce coupling
  • Allow internal changes without breaking other code

Why it matters

If internal details are exposed:

  • Other parts of the program may depend on them.
  • Changing the implementation becomes risky.
  • Bugs can be introduced by uncontrolled modification.

Without Encapsulation​

class BankAccount {
public double balance;
}

Usage:

BankAccount acc = new BankAccount();
acc.balance = -1000000; // Nothing prevents this

Problem:

  • Anyone can assign invalid values.
  • No control over how balance changes.
  • Invariant (balance should not be negative) can be violated.

With Encapsulation (Information Hiding)​

class BankAccount {
private double balance;

public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}

public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}

public double getBalance() {
return balance;
}
}
  • balance is private.
  • Only methods can modify it.
  • Rules are enforced inside the class.
danger

Invariants​

An invariant is a condition that must always be true for an object after construction and between method calls.

Examples:

  • A bank account balance β‰₯ 0
  • A rectangle width > 0 and height > 0
  • A list size β‰₯ 0
  • A person’s age β‰₯ 0

Encapsulation ensures invariants are protected.

Example with Invariant Enforcement​

Let’s define a Rectangle.

Invariant:

  • width > 0
  • height > 0

Bad Design (Invariant Not Protected)​

class Rectangle {
public int width;
public int height;
}

Usage:

Rectangle r = new Rectangle();
r.width = -5; // Violates invariant
r.height = 0; // Also invalid

The object is now in an invalid state.

Proper Encapsulation with Invariant Protection​

class Rectangle {
private int width;
private int height;

public Rectangle(int width, int height) {
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Width and height must be positive.");
}
this.width = width;
this.height = height;
}

public void setWidth(int width) {
if (width <= 0) {
throw new IllegalArgumentException("Width must be positive.");
}
this.width = width;
}

public void setHeight(int height) {
if (height <= 0) {
throw new IllegalArgumentException("Height must be positive.");
}
this.height = height;
}

public int getArea() {
return width * height;
}
}

Now:

  • Object can never exist with invalid dimensions.
  • Invariant is guaranteed after constructor and after each method call.
  • Internal state is protected.

Key Concept: Encapsulation = Protection of Invariants​

You can think of it like this:

ConceptMeaning
Information hidingHide internal state and implementation
Public interfaceControlled access through methods
InvariantCondition that must always hold true
EncapsulationMechanism that ensures invariants cannot be violated

Deep Insight​

Encapsulation is not just about private variables.

It is about:

Designing a class so that it controls its own correctness.
warning

Good encapsulation:

  • Minimizes exposed surface
  • Protects invariants
  • Makes illegal states unrepresentable
  • Allows internal refactoring without breaking users
danger

Advanced View (Language Independent)​

Encapsulation can also mean:

  • Returning copies instead of references (defensive copying)
  • Using immutable objects
  • Restricting mutation
  • Avoiding exposing internal collections

Dangerous:​

public List<String> getItems() {
return items; // exposes internal list
}

Better:

public List<String> getItems() {
return new ArrayList<>(items); // defensive copy
}

This prevents external code from modifying internal state.

Summary​

Encapsulation consists of:

  1. Information Hiding
    • Hide internal data
    • Expose only necessary operations
  2. Invariant Protection
    • Define rules that must always hold
    • Enforce them in constructors and methods
    • Never allow object to enter invalid state
danger

And the golden rule:

If outside code can break your object’s correctness, encapsulation is incomplete.