Skip to main content

1.2 Encapsulation & Access Modifiers

← Back to Chapter 1: OOPs Concepts

Encapsulation is the bundling of data (attributes) and the methods that manipulate that data into a single operational unit, while restricting direct access to an object's internal representation.


1. Why Encapsulation Matters​

  1. Invariable Integrity: Guarantees that internal fields cannot be set to invalid or corrupt states from arbitrary external code.
  2. Implementation Decoupling: You can modify internal data storage (e.g., changing an array to an ArrayList) without breaking external consumer contracts.
  3. Auditability & Observability: Allows logging, validation, security checks, or thread synchronization inside getters/setters.

2. Java Access Modifiers Matrix​

Java has 4 distinct levels of visibility:

ModifierSame ClassSame PackageSubclass (Different Pkg)Everywhere (World)
private✅❌❌❌
(default / package-private)✅✅❌❌
protected✅✅✅❌
public✅✅✅✅
Avoid Public Mutable Fields

Public fields expose internal pointers directly to mutations. Always mark fields private (and final whenever feasible).


3. Defensive Copying: Preventing Leakage​

A common vulnerability occurs when returning mutable references (such as java.util.Date or a java.util.List):

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public final class Department {
private final String name;
private final List<String> employees;

public Department(String name, List<String> employees) {
this.name = name;
// Defensive Copy on Input: Prevents caller from mutating our internal list
this.employees = new ArrayList<>(employees);
}

public String getName() {
return name;
}

// Defensive Copy on Output: Return unmodifiable view or clone
public List<String> getEmployees() {
return Collections.unmodifiableList(employees);
}
}