Chapter 32 of 57

Encapsulation in Java

Imagine you have a bank account. You wouldn't want anyone to directly change your account balance to whatever number they want. Instead, the bank should control how the balance is changed.

This idea is closely related to encapsulation in Java.

Encapsulation means keeping data protected inside a class and controlling how that data can be accessed or modified.

In simple words, instead of allowing other parts of the program to directly access important data, we keep it private and provide controlled methods to work with it.

Why Do We Need Encapsulation?

Let's say we have a BankAccount class:

class BankAccount {
    double balance;
}

Now anyone can directly change the balance:

BankAccount account = new BankAccount();

account.balance = 1000;
account.balance = -5000;

The problem is that nothing is stopping someone from putting an invalid value into balance.

We would rather control how the balance is changed.

This is where encapsulation helps.

Using private

We can make the data private:

class BankAccount {
    private double balance;
}

Now code outside the class cannot directly access balance.

For example:

BankAccount account = new BankAccount();

account.balance = 1000; // Error

Java won't allow this because balance is private.

The data is now protected inside the class.

Getters and Setters

If we need to access or modify private data, we can provide methods for it.

These methods are commonly called getters and setters.

A getter is used to get a value:

public double getBalance() {
    return balance;
}

A setter is used to change a value:

public void setBalance(double balance) {
    this.balance = balance;
}

So our class can look like this:

class BankAccount {
    private double balance;

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}

Now we can use the methods instead of directly accessing the variable:

BankAccount account = new BankAccount();

account.setBalance(1000);

System.out.println(account.getBalance());

Output:

1000.0

Controlling the Data

The real benefit of encapsulation is that we can put rules inside our methods.

For example, a bank account shouldn't have a negative balance in our simple example. Instead of allowing anyone to directly change the value, we can validate it inside the setter.

class BankAccount {
    private double balance;

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        if (balance >= 0) {
            this.balance = balance;
        } else {
            System.out.println("Invalid balance.");
        }
    }
}

Now:

BankAccount account = new BankAccount();

account.setBalance(1000);
account.setBalance(-500);

The second operation will not change the balance because the value is invalid.

This is much safer than allowing direct access to the variable.

Encapsulation Is Not Just Getters and Setters

You'll often hear that encapsulation means private variables with getters and setters. That's a common way to implement it, but the bigger idea is controlling access to an object's internal data.

For example, instead of providing a setter that allows the balance to be changed to any value, we could provide specific methods:

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;
    }
}

Now users of the class don't directly modify balance. They interact with the account through controlled operations such as deposit() and withdraw().

This is a better example of encapsulation because the class itself controls how its internal data can change.

Benefits of Encapsulation

Encapsulation provides several benefits.

Data protection: Important data can be hidden from direct access.

Validation: We can check whether new values are valid before storing them.

Better control: The class decides how its internal data can be used.

Easier maintenance: We can change the internal implementation without necessarily changing how other code uses the class.

A Simple Example

Let's create a simple Student class:

class Student {
    private int age;

    public void setAge(int age) {
        if (age >= 5 && age <= 100) {
            this.age = age;
        } else {
            System.out.println("Invalid age.");
        }
    }

    public int getAge() {
        return age;
    }
}

Now we can use it:

class Main {
    public static void main(String[] args) {

        Student student = new Student();

        student.setAge(20);

        System.out.println("Age: " + student.getAge());
    }
}

Output:

Age: 20

If someone tries:

student.setAge(-10);

the class can reject the value.

The important point is that the age variable itself is hidden, and the class controls how it is accessed and changed.

The Main Idea

Think of encapsulation like a locked box.

The important data is kept inside the box, and instead of letting everyone open it and change things directly, we provide controlled ways to interact with what's inside.

So remember:

Encapsulation = hiding and protecting data while controlling how it is accessed or modified.

In Java, this is commonly achieved using access modifiers such as private along with methods that provide controlled access to the data.