Encapsulation and Data Hiding โ Revision Notes
Encapsulation is the first of the four OOP pillars and an interview certainty โ "name the pillars of OOP and explain encapsulation" opens countless rounds. It shows you can design classes that protect their own invariants.
What encapsulation is
Encapsulation bundles data (fields) and the methods that operate on them into a single unit (the class), and restricts direct access to the internal state. The outside world interacts only through a controlled public interface (getters/setters/methods) โ the object guards its own consistency.
Data hiding is the access-control part: marking fields private so they can't be read/written directly, only via methods that can validate.
Access modifiers
| Modifier | Visible to |
|---|---|
| private | same class only |
| protected | class + subclasses (+ package in Java) |
| public | everyone |
| (default/package) | same package (Java) |
Why it matters
Encapsulation lets you change internal implementation without breaking callers, enforce invariants (e.g. a setter validates that age โฅ 0), and reduce coupling โ the hallmark of maintainable code.
Exam Tricks & Tips
- ๐ฏ Encapsulation = bundling data + methods + access control; data hiding (private fields) is how you achieve it โ don't conflate the two.
- ๐ฏ Getters/setters let you validate and change internals later without altering the public API โ the practical reason for private fields.
- ๐ฏ In Python there's no true private โ a leading underscore
_xis a convention, and__xtriggers name-mangling, not real hiding. - ๐ฏ
privateis the most restrictive,publicthe least;protectedsits between (adds subclasses). - ๐ฏ Encapsulation reduces coupling, so a change in one class ripples less to others โ a common "why encapsulate?" answer.
- ๐ฏ Immutability (private final fields, no setters) is a strong form of encapsulation for thread-safety.
- โ Common mistake: confusing encapsulation with abstraction โ abstraction hides complexity/what, encapsulation hides data/how and bundles it.
Expected pattern
"Define encapsulation", "encapsulation vs abstraction", "why make fields private?", "list access modifiers", and "how does Python do encapsulation?".
Quick recap
Encapsulation bundles data + behaviour in a class and restricts direct access (data hiding via private). Interact through getters/setters that can validate. Modifiers: private < protected < public. It cuts coupling and lets internals change freely. Distinct from abstraction (which hides complexity).
Encapsulation and Data Hiding โ Flashcards
Cover the answer, recall, then check. 11 cards on encapsulation and data hiding.
Q1. What is encapsulation?
A1. Bundling data and the methods that act on it into one class, and restricting direct external access to that data.
Q2. What is data hiding?
A2. Restricting direct access to an object's internal fields (e.g. making them private), exposing them only through controlled methods.
Q3. Why use private fields with getters/setters?
A3. To validate/control access and change the internal implementation later without breaking the public API.
Q4. List the access modifiers from most to least restrictive (Java).
A4. private โ (package-default) โ protected โ public.
Q5. What can access a protected member?
A5. The class itself, its subclasses, and (in Java) classes in the same package.
Q6. Does Python have true private members?
A6. No โ a leading underscore is a convention; a double underscore triggers name-mangling, not enforced privacy.
Q7. How does encapsulation differ from abstraction?
A7. Encapsulation hides/bundles data (the "how"); abstraction hides complexity and exposes only essential behavior (the "what").
Q8. How does encapsulation reduce coupling?
A8. Callers depend only on the public interface, so internal changes don't ripple out to dependent classes.
Q9. What is one benefit of validating input inside a setter?
A9. It enforces object invariants (e.g. rejecting a negative age), keeping the object in a always-valid state.
Q10. Which OOP pillar does encapsulation belong to?
A10. It is one of the four pillars: encapsulation, abstraction, inheritance, and polymorphism.
Q11. How does immutability relate to encapsulation?
A11. Making fields private and final with no setters is a strong encapsulation form that also gives thread-safety.
Encapsulation and Data Hiding
Encapsulation is the first of the four OOP pillars and the one most often confused with "using getters and setters". It is really about controlling access to protect an object's internal state โ and understanding why is what separates a rote answer from a strong one.
Core idea: encapsulation bundles data and the methods that operate on it into one unit (a class) and restricts direct access to that data, exposing only a controlled public interface. Data hiding is the access-restriction half โ making fields private so outside code cannot reach in and corrupt them.
How it works
Beginner โ bundling + access control
class BankAccount {
private double balance; // hidden state
public void deposit(double amt) { // controlled interface
if (amt > 0) balance += amt; // invariant enforced here
}
public double getBalance() { return balance; }
}
The field is private, so no external code can write account.balance = -999. Every change funnels through deposit/withdraw, which can enforce rules.
Intermediate โ access modifiers
Most OO languages provide visibility levels (Java example): public (everyone), protected (class + subclasses + package), default/package (same package), private (this class only). C++ uses public/protected/private; Python uses convention (_name "internal", __name name-mangled). The principle is the same: expose the minimum necessary.
Advanced โ invariants and why hiding matters
The real payoff is class invariants โ conditions that must always hold (e.g. balance >= 0). If balance were public, any code could violate the invariant and the bug could originate anywhere. With it private, only the class's own methods can change it, so validation lives in one place and bugs are localised. Encapsulation also enables change without breaking callers: you can switch balance from a field to a computed value, and callers using getBalance() never notice.
// Later: balance becomes derived; the public method shields callers
public double getBalance() { return sumOfTransactions(); }
Worked example โ enforcing an invariant
class Temperature {
private double celsius = 0;
public void set(double c) {
if (c < -273.15) throw new IllegalArgumentException("below absolute zero");
celsius = c; // guaranteed valid
}
public double get() { return celsius; }
}
Temperature t = new Temperature();
// t.celsius = -500; // COMPILE ERROR: private -> cannot bypass validation
t.set(25); // allowed
Because celsius is unreachable from outside, every path to change it passes the set guard. Making the field public would let callers create physically impossible states, and you would have no single place to defend the invariant.
Interview & exam relevance
Common asks: "what is encapsulation and how is it different from abstraction?" (encapsulation hides data and bundles behaviour; abstraction hides complexity/implementation), "why are getters/setters used?" (controlled access, validation, future flexibility), and access-modifier semantics. A strong answer stresses invariants, not just "make fields private".
Tricks & gotchas
- A getter/setter that just reads/writes a field with no logic adds little โ encapsulation's value is the ability to add validation and to change internals later.
- Returning a reference to a mutable internal field (e.g. a
List) breaks encapsulation โ callers can mutate it directly; return a copy or an unmodifiable view. protectedis more open than beginners expect (often package-visible too).- Mnemonic: "Encapsulate = capsule: data + methods sealed together."
Equating encapsulation with "just add getters and setters". Blindly exposing every field through a setter that does no validation is barely better than making the field public โ you have preserved none of the protection. Encapsulation's point is a controlled interface that guards invariants, not mechanical accessor generation.
- โ- Encapsulation bundles data with its methods and restricts direct access.
- โ- Data hiding (private fields) forces changes through validated methods.
- โ- Access modifiers (
public/protected/private) express the minimum-exposure principle. - โ- The payoff: enforce invariants in one place and change internals without breaking callers.
- โ- Never leak mutable internals; return copies or read-only views.
- โEncapsulation seals data and behaviour into a class and hides the data behind a controlled interface, so invariants are enforced in one place and internal changes don't ripple to callers. It's about protection and flexibility, not mechanical accessors.
Encapsulation and Data Hiding โ Worked Example
Worked Example
Problem: A BankAccount exposes its balance as a public field, and a bug lets the balance go negative. Redesign it with encapsulation so the invariant "balance โฅ 0" cannot be violated, and explain what data hiding buys you.
// Before: no protection
class BankAccount { public double balance; }
acct.balance = -500; // nothing stops this
Solution:
Encapsulation bundles data with the methods that operate on it and restricts direct access, so the object controls its own state. We make the field private (data hiding) and expose behaviour through methods that enforce the invariant:
class BankAccount {
private double balance; // hidden state
public BankAccount(double initial) {
if (initial < 0) throw new IllegalArgumentException("negative");
balance = initial;
}
public double getBalance() { return balance; } // read-only accessor
public void deposit(double amt) {
if (amt <= 0) throw new IllegalArgumentException("amt<=0");
balance += amt;
}
public void withdraw(double amt) {
if (amt <= 0 || amt > balance) // invariant guard
throw new IllegalArgumentException("invalid withdrawal");
balance -= amt;
}
}
Now acct.balance = -500 is a compile error โ outside code cannot touch balance directly. Every mutation goes through deposit/withdraw, which validate arguments and keep balance โฅ 0. There is no public setter, so the balance is read-only from outside; it changes only via meaningful operations.
Benefits: the invariant lives in one place; internal representation can change (e.g. store cents as a long) without breaking callers, since they depend only on the public methods, not the field.
Answer: Make balance private and provide validated deposit/withdraw plus a read-only getBalance. Direct assignment becomes impossible, so the "balance โฅ 0" invariant is enforced centrally and the internal representation stays free to change.
- โ- Encapsulation = bundle data with behaviour and hide the data; mutate only through validated methods.
- โ- Private fields let a class enforce invariants in one place, blocking illegal external assignments.
- โ- Hiding the representation lets internals change without breaking callers who depend only on the public API.