Encapsulation

Encapsulation

A school program needs reliable data and clear rules. Encapsulation keeps related state and behavior together and controls valid changes. A mark setter can reject values outside the school’s 0–100 rule.

  1. Understand

    Encapsulation keeps related state and behavior together and controls valid changes.

  2. Apply

    Trace the Java example, predict its output and explain the result before running it.

  3. Avoid mistakes

    Getters and setters alone do not guarantee a sound design. The methods must preserve meaningful rules.

Encapsulation

Encapsulation in Java means keeping the data (variables) and the code (methods) that work on that data together in one place — a class. It helps protect the data by hiding it from outside access. Instead of letting other code directly change the variables, we use special methods to control how the data is accessed or updated. This is called data hiding.

How to Implement Encapsulation in Java

Let’s break it down into simple steps so it’s easy to understand:

Step 1: Make variables private

This means the variables (fields) can only be used inside the class where they are declared. They are hidden from other classes.

Step 2: Create public getter and setter methods

These methods let other classes safely get (read) or set (change) the values of the private variables. This way, you control how the data is accessed or updated.

Example: Encapsulating a Bank Account

  public class BankAccount {
    private String accountHolder;
    private double balance;

    // Constructor
    public BankAccount(String name, double initialBalance) {
        accountHolder = name;
        balance = initialBalance;
    }

    // Getter for accountHolder
    public String getAccountHolder() {
        return accountHolder;
    }

    // Setter for accountHolder
    public void setAccountHolder(String name) {
        accountHolder = name;
    }

    // Getter for balance
    public double getBalance() {
        return balance;
    }

    // Setter for balance
    public void setBalance(double amount) {
        if (amount >= 0) {
            balance = amount;
        } else {
            System.out.println("Balance cannot be negative.");
        }
    }
}

Using the Encapsulated Class

  public class BankAccount {
    private String accountHolder;
    private double balance;

    // Constructor
    public BankAccount(String name, double initialBalance) {
        accountHolder = name;
        balance = initialBalance;
    }

    // Getter for accountHolder
    public String getAccountHolder() {
        return accountHolder;
    }

    // Setter for accountHolder
    public void setAccountHolder(String name) {
        accountHolder = name;
    }

    // Getter for balance
    public double getBalance() {
        return balance;
    }

    // Setter for balance
    public void setBalance(double amount) {
        if (amount >= 0) {
            balance = amount;
        } else {
            System.out.println("Balance cannot be negative.");
        }
    }
}
    
public class Main {
    public static void main(String[] args) {
        BankAccount account = new BankAccount("Alice", 5000);

        // Accessing data via getters
        System.out.println("Account Holder: " + account.getAccountHolder());
        System.out.println("Initial Balance: $" + account.getBalance());

        // Modifying data via setters
        account.setBalance(7000);
        System.out.println("Updated Balance: $" + account.getBalance());

        // Trying to set invalid balance
        account.setBalance(-100);
    }
}
Account Holder: Alice
Initial Balance: $5000.0
Updated Balance: $7000.0
Balance cannot be negative.

What Happens If You Skip Encapsulation?

If fields were public, any class could change the values without any checks. For instance:

account.balance = -10000; // This would be allowed if 'balance' was public

This is dangerous. You lose control over your class’s integrity. With encapsulation, such reckless modifications can be blocked.

Why Encapsulation Matters

Without encapsulation, our classes would be exposed — any part of the codebase could directly modify the internal state of objects. That’s a recipe for unpredictable behavior. Encapsulation ensures:

  • Control over how the internal data is accessed or modified.
  • Improved security by hiding sensitive fields.
  • Cleaner, more maintainable code.

Benefits of Encapsulation at Scale

  • In large systems, encapsulation allows teams to work independently on different components without worrying about each other's internal logic.
  • Helps enforce business rules via logic inside setters (e.g., disallowing negative balances).
  • Improves testing and debugging by narrowing down where changes can happen.

Real-World Analogy

Think of encapsulation like using a vending machine. You interact with it through buttons (public methods) — you don’t get to reach inside and grab a drink (private fields). It controls what happens internally based on your input.

Recap

  • Encapsulation = combining data + methods + access control
  • Use private for fields
  • Use public getters and setters to expose controlled access

Important boundaries and mistakes

Getters and setters alone do not guarantee a sound design. The methods must preserve meaningful rules.

Try the school example

Before running this Java program, write down each line you expect to see. Identify the value, branch, object or exception responsible for each line. Then explain whether the following assumption is valid: Getters and setters alone do not guarantee a sound design.

Java 17 · Main.java · complete practice program

class Record  {
  private int mark;
  void setMark(int value)  {
    if (value < 0 || value > 100) throw new IllegalArgumentException("mark");
    mark = value;
  }
  int getMark()  {
    return mark;
  }
}
public class Main  {
  public static void main(String[] args)  {
    Record s = new Record();
    s.setMark(72);
    System.out.println(s.getMark());
  }
}

Now change one thing: Call setMark(101). Predict the new behavior before checking the worked variation.

Worked answer and reasoning

Java 17 · Main.java · source repeated for this answer

class Record  {
  private int mark;
  void setMark(int value)  {
    if (value < 0 || value > 100) throw new IllegalArgumentException("mark");
    mark = value;
  }
  int getMark()  {
    return mark;
  }
}
public class Main  {
  public static void main(String[] args)  {
    Record s = new Record();
    s.setMark(72);
    System.out.println(s.getMark());
  }
}

Expected output

72

Encapsulation keeps related state and behavior together and controls valid changes. A mark setter can reject values outside the school’s 0–100 rule.

Getters and setters alone do not guarantee a sound design. The methods must preserve meaningful rules.

Run with javac Main.java, then java Main. The declaration inside Main keeps the helper type available to this standalone example.

Worked variation: Call setMark(101). The range check rejects it with IllegalArgumentException before changing the stored mark.

Check your understanding

For the complete practice program in this lesson, which output is expected on Java 17?
Choose one answer. You can try again.

Answer and explanation

72

Encapsulation keeps related state and behavior together and controls valid changes. A mark setter can reject values outside the school’s 0–100 rule. Getters and setters alone do not guarantee a sound design. The methods must preserve meaningful rules.

What to remember

Encapsulation keeps related state and behavior together and controls valid changes. A mark setter can reject values outside the school’s 0–100 rule. Getters and setters alone do not guarantee a sound design. The methods must preserve meaningful rules.

Related explanations: Java Variables, Java If Statement - Syntax and Examples, Java Class - Blueprint of Objects, Exceptions in Java Introduction.

Supporting documentation: Official Java learning guide and Java 17 language specification.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Nested Classes →