Classes and Objects · Lesson 22 of 42
Encapsulation, Access Modifiers and Packages
In the first lesson of this chapter anyone could write account.balance = -99999;. Real code can't allow that. Encapsulation means hiding an object's data and exposing only safe operations, so the object can always protect its own rules. It is the first of the four pillars of object-oriented programming.
In this lesson
- Private fields with getters and validated setters
- The four access levels: public, protected, default, private
- Packages and imports
- Immutable classes
Encapsulation in practice
public class Main {
public static void main(String[] args) {
BankAccount acc = new BankAccount("Meena", 1000);
acc.withdraw(300);
System.out.println(acc.getOwner() + " has ₹" + acc.getBalance());
try {
acc.withdraw(5000);
} catch (IllegalStateException e) {
System.out.println("Blocked: " + e.getMessage());
}
// acc.balance = 1_000_000; → error: balance has private access
}
}
class BankAccount {
private final String owner;
private double balance; // hidden: only this class can touch it
BankAccount(String owner, double opening) {
this.owner = owner;
deposit(opening);
}
public double getBalance() { // read access
return balance;
}
public String getOwner() {
return owner;
}
public void deposit(double amount) {
if (amount <= 0) throw new IllegalArgumentException("Deposit must be positive");
balance += amount;
}
public void withdraw(double amount) {
if (amount > balance) throw new IllegalStateException("Insufficient funds");
balance -= amount;
}
}
Meena has ₹700.0 Blocked: Insufficient funds
Encapsulated object
- Public methodsdeposit(), withdraw(), getBalance() – the safe interface
- Rules insideamount must be positive, no overdraft
- Private databalance – unreachable from outside
Notice there is no setBalance(). Good encapsulation doesn't mean a getter and setter for every field – it means exposing only the operations that make sense for the object.
Access modifiers
| Modifier | Same class | Same package | Subclass (other package) | Everywhere |
|---|---|---|---|---|
private | ✓ | ✗ | ✗ | ✗ |
| (default – no keyword) | ✓ | ✓ | ✗ | ✗ |
protected | ✓ | ✓ | ✓ | ✗ |
public | ✓ | ✓ | ✓ | ✓ |
A practical default: make fields private, make methods public only if other classes need them, and use protected sparingly for things subclasses must customise. A top-level class can only be public or default.
Common mistake: public fields
A public field can be set to any value from anywhere, and you can never add validation later without breaking every caller. Keep fields private from day one.
Getters and setters with validation
public class Main {
public static void main(String[] args) {
Employee e = new Employee();
e.setName(" Farah Khan ");
e.setAge(29);
System.out.println("[" + e.getName() + "] " + e.getAge());
try {
e.setAge(12);
} catch (IllegalArgumentException ex) {
System.out.println(ex.getMessage());
}
}
}
class Employee {
private String name;
private int age;
public String getName() { return name; }
public void setName(String name) {
if (name == null || name.isBlank()) throw new IllegalArgumentException("Name required");
this.name = name.strip();
}
public int getAge() { return age; }
public void setAge(int age) {
if (age < 18 || age > 65) throw new IllegalArgumentException("Age must be 18–65");
this.age = age;
}
}
[Farah Khan] 29 Age must be 18–65
The naming convention getX / setX (and isX for booleans) matters: frameworks such as Spring, Hibernate and Jackson use it to read and write your objects automatically.
Packages and imports
A package groups related classes, like folders, and gives them unique full names. Package names are lowercase and usually start with a reversed domain:
src/
└── com/learnfrenzy/bank/
├── BankAccount.java // package com.learnfrenzy.bank;
└── service/
└── TransferService.java // package com.learnfrenzy.bank.service;
package com.learnfrenzy.bank.service;
import com.learnfrenzy.bank.BankAccount; // one class
import java.util.*; // every class in java.util (not sub-packages)
public class TransferService {
public void transfer(BankAccount from, BankAccount to, double amount) {
from.withdraw(amount);
to.deposit(amount);
}
}
java.lang(String, Math, Integer, System…) is imported automatically.- If two packages have a class with the same name (
java.util.Dateandjava.sql.Date), use the full name for one of them. - Default (package-private) access lets classes in the same package cooperate while hiding details from the rest of the application.
Immutable classes
An immutable object can't change after creation – like String. Immutable objects are simple to reason about and safe to share between threads.
import java.util.List;
public class Main {
public static void main(String[] args) {
Money a = new Money(19_999, "INR");
Money b = a.plus(new Money(5_001, "INR"));
System.out.println(a + " | " + b);
List<String> fixed = List.of("read-only");
System.out.println(fixed);
}
}
final class Money { // final: no subclass can add mutability
private final long paise; // final fields, set once
private final String currency;
Money(long paise, String currency) {
this.paise = paise;
this.currency = currency;
}
Money plus(Money other) { // "changes" return a new object
return new Money(paise + other.paise, currency);
}
@Override
public String toString() {
return String.format("%s %.2f", currency, paise / 100.0);
}
}
INR 199.99 | INR 250.00 [read-only]
Java 16+ records (chapter 10) create classes like this in a single line.
Practice
Try it yourself
Write a
Temperatureclass with a private Celsius field, a setter that rejects values below −273.15, and agetFahrenheit()method.Show solution
public class Main { public static void main(String[] args) { Temperature t = new Temperature(); t.setCelsius(30); System.out.println(t.getFahrenheit()); } } class Temperature { private double celsius; public void setCelsius(double c) { if (c < -273.15) throw new IllegalArgumentException("Below absolute zero"); celsius = c; } public double getFahrenheit() { return celsius * 9 / 5 + 32; } }86.0
Quick check
Which access level has no keyword?
Default (package-private): visible within the same package only.
Does encapsulation mean a getter and setter for every field?
No – expose only the operations the object should support, and validate them.
Which package is imported automatically?
java.lang
Summary
- Encapsulation: private data, public operations that enforce the rules.
- Access: private < default < protected < public.
- Packages organise classes; immutable classes use final fields and return new objects for changes.
Interview practice: Java OOP in depth.
Finished this lesson?
Mark it complete to track your progress, then carry on with the next lesson.