Shiklo Programming
EN
  • English
  • Español
  • Português
  • Deutsch
  • Français
  • 日本語
  • हिन्दी

Java Encapsulation

Encapsulation means keeping an object's data private and letting other code change it only through the object's own methods. The object becomes responsible for its data: it can check every change, refuse bad values and keep everything consistent. It is one of the main ideas of object-oriented programming, and it builds directly on the private modifier from Modifiers.

Getters and setters

The usual pattern is: private fields, a public getter to read each one, and a public setter to change it where changing makes sense. By convention they are named getX and setX (and isX for booleans):

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        setAge(age);
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age < 0 || age > 150) {
            System.out.println("Ignored impossible age: " + age);
            return;
        }
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person p = new Person("Kavya", 28);
        p.setAge(29);
        p.setAge(-4);
        System.out.println(p.getName() + " is " + p.getAge());
    }
}
Output
Ignored impossible age: -4
Kavya is 29

The constructor also uses setAge, so the same check protects new objects. A program can no longer create a person aged -4 by accident.

Read-only data

If a field has a getter but no setter, other classes can read it but never change it. Combined with final this makes data that is fixed once the object exists:

class Order {
    private final String id;
    private int quantity;

    public Order(String id, int quantity) {
        this.id = id;
        this.quantity = quantity;
    }

    public String getId() {
        return id;
    }

    public int getQuantity() {
        return quantity;
    }

    public void addOne() {
        quantity++;
    }
}

public class Main {
    public static void main(String[] args) {
        Order o = new Order("A-17", 2);
        o.addOne();
        System.out.println(o.getId() + ": " + o.getQuantity() + " items");
    }
}
Output
A-17: 3 items

The quantity can only grow through addOne, and the ID cannot change at all.

Keeping data consistent

Encapsulation shines when fields depend on each other. Here the class keeps the total of all marks in step with the number of marks, so average is always right:

class Marks {
    private int count;
    private int total;

    public void add(int mark) {
        if (mark >= 0 && mark <= 100) {
            count++;
            total += mark;
        }
    }

    public double average() {
        return count == 0 ? 0 : (double) total / count;
    }
}

public class Main {
    public static void main(String[] args) {
        Marks m = new Marks();
        m.add(80);
        m.add(90);
        m.add(250);
        m.add(70);
        System.out.println("Average: " + m.average());
    }
}
Output
Average: 80.0

If other code could change count or total directly, the average could become wrong. Because both are private, add is the only way in, and it changes them together.

Why it matters

  • Safety: bad values are refused in one place.
  • Freedom to change: the class can store its data differently later (for example in paise instead of rupees) without breaking the code that uses it, because that code only calls the methods.
  • Clarity: the public methods describe what an object can do; the details stay hidden.

The Records topic shows a short way to write simple classes whose data never changes.

Practice exercises

  1. Write a class Temperature with a private celsius field, a getter, and a setter that refuses values below -273.15.
  2. Add a getter getFahrenheit() that is calculated from celsius instead of stored.
  3. Write a class Counter whose value can only be increased by increment() and read by getValue().