Encapsulation & Access Modifiers — Hide, Protect, Expose
Encapsulation ও Access Modifier — ডেটা লুকান, সুরক্ষিত করুন, প্রয়োজনমতো প্রকাশ করুন
1. Why Hide Anything at All?
Encapsulation means bundling data and the methods that work on that data together inside a class, and then hiding the data so the rest of the program can only touch it through well-defined methods. Imagine a bank account: you cannot walk up to a teller and set the balance to any number you want. You can deposit, withdraw, or query — and each of those operations enforces rules (non-negative balance, valid amounts, audit logs). The internal balance field is hidden; the operations are public.
This module shows Java's four access levels, the getter/setter idiom, and the immutable-class pattern that modern Java strongly prefers.
2. The Four Access Levels
Java gives you four visibility levels, from most restrictive to most open:
| Modifier | Same class | Same package | Subclass | Everywhere |
|---|---|---|---|---|
private | ✅ | ❌ | ❌ | ❌ |
| package-private (no keyword) | ✅ | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ | ✅ |
private → শুধু নিজ class-এ দেখা যায়। কিছু না লিখলে (default / package-private) → একই package-এর class-গুলো দেখতে পায়। protected → package + subclass। public → সর্বত্র। সাধারণ নিয়ম: যতটা সীমাবদ্ধ রাখা যায় ততটা ভালো।
3. Private Fields + Public Methods — The Classic Pattern
Declare every field private and expose only what callers truly need. The code below is a
Bangladesh-style bank account: the balance is hidden, and the only way in or out is through methods that
enforce invariants (amount must be positive, withdraw cannot overdraw).
private রাখুন, বাইরে থেকে কেবল দরকারি method দিয়ে access দিন। নিচে একটি bank account — balance লুকানো, deposit/withdraw method নিয়ম enforce করে (amount positive, overdraw নয়)।
class BankAccount {
private String holder;
private double balance;
BankAccount(String holder, double opening) {
this.holder = holder;
this.balance = Math.max(0, opening);
}
public void deposit(double amount) {
if (amount <= 0) throw new IllegalArgumentException("amount must be positive");
balance += amount;
}
public void withdraw(double amount) {
if (amount <= 0) throw new IllegalArgumentException("positive only");
if (amount > balance) throw new IllegalStateException("insufficient funds");
balance -= amount;
}
public double getBalance() { return balance; }
public String getHolder() { return holder; }
}
class Main {
public static void main(String[] args) {
BankAccount a = new BankAccount("Nadia", 10000);
a.deposit(5000);
a.withdraw(2000);
System.out.println(a.getHolder() + " → BDT " + a.getBalance());
}
}
double to BigDecimal). That freedom-to-change is the real reward
of encapsulation.
মূল কথা: বাইরের API একই থাকলেও ভেতরে representation পরিবর্তন সম্ভব — এটাই encapsulation-এর বড় পুরস্কার।
4. The Immutable Class Pattern
A class is immutable when its state cannot change after construction. Recipe:
- Declare the class
final(no subclassing). - Declare every field
private final. - Initialise every field in the constructor.
- Provide getters only — no setters.
- If a field is itself mutable (e.g. a list), defensively copy it in the constructor and the getter.
final, সব field private final, constructor-এ সেট, শুধু getter, mutable field হলে defensive copy।
final class Point {
private final double x;
private final double y;
Point(double x, double y) { this.x = x; this.y = y; }
public double getX() { return x; }
public double getY() { return y; }
// "setter" returns a NEW object — the original is untouched
public Point translate(double dx, double dy) {
return new Point(x + dx, y + dy);
}
}
class Main {
public static void main(String[] args) {
Point p = new Point(2, 3);
Point q = p.translate(5, 5);
System.out.println("p=(" + p.getX() + "," + p.getY() + ")");
System.out.println("q=(" + q.getX() + "," + q.getY() + ")");
}
}
5. Getter/Setter Style — and When to Skip Them
Blindly adding a setter for every field is an anti-pattern — it defeats the purpose of hiding the data in the first place. Ask: does the outside world actually need to change this? Often the answer is no and you should expose only a getter (or better yet, no accessor at all, via a meaningful domain method).
deposit)।
✅ Good
deposit(amount)withdraw(amount)getBalance()
⚠️ Lazy & Dangerous
setBalance(newBalance)— lets anyone overwrite!- Public field:
account.balance = -10_000;
6. Vocabulary (শব্দভাণ্ডার)
| Term | Meaning | বাংলায় |
|---|---|---|
| Encapsulation | Bundling data + methods and hiding the data. | ডেটা ও method একসাথে রেখে ডেটা লুকিয়ে রাখা। |
private | Visible only inside the same class. | শুধু নিজ class-এ দৃশ্যমান। |
public | Visible everywhere. | সর্বত্র দৃশ্যমান। |
protected | Package + subclasses. | Package ও subclass-এ দৃশ্যমান। |
| Package-private | No modifier — visible only in the same package. | কোনো modifier নেই — একই package-এ দৃশ্যমান। |
| Getter/Setter | Method pair that reads/writes a private field. | Private field পড়ার ও লেখার জন্য method জোড়া। |
| Immutable | State never changes after construction. | তৈরির পর state আর পরিবর্তন হয় না। |
7. Practice Problems
-
Write an
Employeeclass with a privatesalaryfield and a publicraise(double percent)method that rejects any negative raise.Employeeclass লিখুন — privatesalary, এবংraise(double percent)method যেটি negative raise reject করবে।✨ Show Answer
Main.javaclass Employee { private String name; private double salary; Employee(String n, double s) { name = n; salary = s; } public void raise(double pct) { if (pct < 0) throw new IllegalArgumentException("no pay cuts here"); salary *= (1 + pct / 100); } public double getSalary() { return salary; } } class Main { public static void main(String[] args) { Employee e = new Employee("Sumi", 40000); e.raise(10); System.out.println("New salary: " + e.getSalary()); } } -
In two sentences, why is a public field worse than a public getter that returns the same value?দুই বাক্যে — একটি public field-এর চেয়ে একই মান ফেরত দেওয়া public getter কেন ভালো?
✨ Show Answer
Answer: A public field forever binds callers to that exact name, type, and representation — changing any of those is a breaking change. A getter is a method, so you can later change the field (rename it, compute it, back it with a cache) without touching a single caller.
Public field callers-কে field-এর নাম, type ও representation-এর সাথে চিরতরে বেঁধে ফেলে — পরে বদলালে সব caller ভাঙবে। Getter method হওয়ায় ভেতরের field আপনি ইচ্ছামতো বদলাতে পারবেন, caller-এ ধাক্কা লাগবে না।
-
Make an immutable
Moneyclass withamount(long paisa) andcurrency(String). Add a methodplus(Money other)that returns a newMoneywhen currencies match, else throws.একটি immutableMoneyclass বানান (amount: long paisa, currency: String)।plus(Money other)method মুদ্রা মিললে নতুনMoneyদেবে, না মিললে throw করবে।✨ Show Answer
Main.javafinal class Money { private final long amount; private final String currency; Money(long a, String c) { amount = a; currency = c; } public Money plus(Money o) { if (!currency.equals(o.currency)) throw new IllegalArgumentException("currency mismatch"); return new Money(amount + o.amount, currency); } public String toString() { return amount + " " + currency; } } class Main { public static void main(String[] args) { Money a = new Money(5000, "BDT"); Money b = new Money(2500, "BDT"); System.out.println(a.plus(b)); } } -
Show a
Temperatureclass that stores Celsius privately but exposes getters for both Celsius and Fahrenheit — no setter.একটিTemperatureclass বানান — private-এ Celsius রাখবে, getter দেবে Celsius ও Fahrenheit দুইয়ের, কোনো setter থাকবে না।✨ Show Answer
Main.javafinal class Temperature { private final double celsius; Temperature(double c) { celsius = c; } public double getCelsius() { return celsius; } public double getFahrenheit() { return celsius * 9 / 5 + 32; } } class Main { public static void main(String[] args) { Temperature t = new Temperature(30); System.out.println(t.getCelsius() + "C = " + t.getFahrenheit() + "F"); } } -
In 2–3 sentences, explain what "package-private" means and when you might prefer it over
public.দুই-তিন বাক্যে — package-private কী এবং কখন একেpublic-এর চেয়ে ভালো মনে হয়?✨ Show Answer
Answer: Package-private (no modifier) means the class or member is visible only to other classes in the same package — the outside world cannot see it at all. Prefer it for helper classes and methods that are implementation details of a module: other packages cannot even depend on them, so you are free to refactor them without breaking anyone.
Package-private (কোনো modifier না দিলে) মানে একই package-এর class ছাড়া কেউ দেখতে পাবে না। Helper class/method-কে package-private রাখুন — অন্য package এদের উপর depend করতে পারবে না, তাই refactor-এ ভয় নেই।
Summary — Module 13
Encapsulation bundles data with the methods that guard it and hides the data from the
outside world. Java enforces this with four access modifiers — private, package-private,
protected, and public — in increasing order of visibility. The everyday recipe is:
fields private, behaviour public, getters yes-when-needed, setters sparingly or
never. The strongest form is the immutable class: once built, its state cannot change —
which removes an entire category of bugs and makes classes inherently thread-safe.
private, package-private, protected, public — ছোট থেকে বড় দৃশ্যমানতা। অভ্যাস: field private, behaviour public, getter দরকারমতো, setter যতটা কম ততটা ভালো। সবচেয়ে শক্তিশালী রূপ — immutable class, যা একবার তৈরি হওয়ার পর বদলায় না।