Encapsulation is the first and arguably most important pillar of Object-Oriented Programming. It is the mechanism of wrapping the data (variables) and the code acting on the data (methods) together as a single unit, and then restricting direct access to some of the object's components.
Think of a capsule (pill). A capsule encases medicine inside a protective shell. You don't need to know the chemical formula inside; you just swallow it. Similarly, an encapsulated class hides its internal data behind a protective layer of methods.
The core principle: an object's data should NEVER be directly accessible from outside the object. All interaction with the data must happen through the object's own methods.
class BankAccount {
public double balance; // Anyone can access this!
}
BankAccount acc = new BankAccount();
acc.balance = -999999; // A bug sets balance to negative. No validation!
class BankAccount {
private double balance; // Hidden from the outside world
public void deposit(double amount) {
if (amount > 0) { // Validation logic!
this.balance += amount;
}
}
public double getBalance() {
return this.balance;
}
}
BankAccount acc = new BankAccount();
// acc.balance = -999999; // COMPILE ERROR! Cannot access private field.
acc.deposit(500); // The only way to modify balance is through the validated method.
Access Modifiers are keywords that control the visibility and accessibility of classes, methods, and variables. They are the enforcement mechanism for encapsulation.
private: Accessible only within the same class. Not visible to any other class, not even subclasses. This is the default choice for all class attributes.default (no keyword): Accessible only within the same package. Not visible to classes in other packages.protected: Accessible within the same package, AND by subclasses (even if the subclass is in a different package).public: Accessible from absolutely anywhere. Any class in the entire project can access it.| Modifier | Same Class | Same Package | Subclass (Diff Package) | World |
|---|---|---|---|---|
private | Yes | No | No | No |
default | Yes | Yes | No | No |
protected | Yes | Yes | Yes | No |
public | Yes | Yes | Yes | Yes |
If all data is private, how does the outside world interact with it? Through Getter and Setter methods (also called Accessor and Mutator methods).
public method that returns the value of a private variable.public method that sets the value of a private variable, often including validation logic.class Employee {
private String name;
private int age;
// Getter
public String getName() {
return this.name;
}
// Setter with validation
public void setAge(int age) {
if (age >= 18 && age <= 65) {
this.age = age;
} else {
throw new IllegalArgumentException("Age must be between 18 and 65");
}
}
}
This pattern gives the class author complete, centralized control over how its data is read and modified, making debugging trivial compared to procedural code where any function could silently corrupt the data.