Dung (Donny) Nguyen

Senior Software Engineer

The 4 Pillars of Object-Oriented Programming (OOP)

Object-oriented programming organizes software around objects — self-contained units that combine data and behavior. Java is built on four foundational principles, often called the four pillars of OOP: Encapsulation, Inheritance, Polymorphism, and Abstraction. Together they help you write code that is modular, reusable, and easy to maintain.

Encapsulation

Definition: Encapsulation is the bundling of data (fields) and the methods that operate on that data into a single unit — a class — while restricting direct access to the internal state.

Purpose: It protects data from unauthorized or accidental modification, hides implementation details, and lets you change the internals of a class without breaking the code that uses it. This is often called data hiding.

How it works in Java:

Example:

public class BankAccount {
    private double balance; // hidden from outside access

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {
        if (amount > 0) {          // validation protects the data
            balance += amount;
        }
    }

    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }
}

Because balance is private, no external code can set it to an invalid value directly. Every change must go through deposit() or withdraw(), which enforce the rules.

Inheritance

Definition: Inheritance establishes an “is-a” relationship between classes, where a subclass (child) inherits fields and methods from a superclass (parent).

Purpose: It promotes code reuse, models real-world hierarchies, and enables polymorphism. Common behavior lives in the parent class, while specialized behavior is added or overridden in child classes.

How it works in Java:

Example:

public class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void makeSound() {
        System.out.println(name + " makes a sound");
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name); // call the parent constructor
    }

    @Override
    public void makeSound() {
        System.out.println(name + " barks");
    }
}

Here Dog is an Animal. It reuses the name field and constructor logic while overriding makeSound() with its own behavior.

Polymorphism

Definition: Polymorphism (“many forms”) is the ability of objects of different classes to respond to the same method call in different ways.

Purpose: It makes code flexible and extensible. You can write code that works with a general type, and the correct implementation is selected automatically at runtime.

Two types in Java:

Runtime polymorphism lets you treat a Dog or a Cat as an Animal while each still behaves according to its own class.

Abstraction

Definition: Abstraction means exposing only the essential features of an object while hiding the complex implementation details.

Purpose: It reduces complexity, defines clear contracts, and lets callers focus on what an object does rather than how it does it.

How it works in Java:

Example with an abstract class:

public abstract class Shape {
    public abstract double area(); // no implementation — subclasses must provide it

    public void describe() {       // shared concrete behavior
        System.out.println("This shape has an area of " + area());
    }
}

public class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

Example with an interface:

public interface Drawable {
    void draw();
}

public class Button implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a button");
    }
}

Callers only need to know that a Shape has an area() or that a Drawable can draw() — the details are hidden behind the abstraction.

Abstract Class vs. Interface

Aspect Abstract Class Interface
Instantiation Cannot be instantiated Cannot be instantiated
Methods Abstract and concrete methods Abstract methods; default and static methods since Java 8
Fields Instance fields allowed Only public static final constants
Inheritance A class extends only one A class implements many
Use when Classes share state and behavior You need a common contract across unrelated classes

Summary

Pillar Core Idea Key Java Feature
Encapsulation Bundle data with behavior and hide internals private fields, getters/setters
Inheritance Reuse and extend existing classes extends, super
Polymorphism One interface, many implementations Overloading and overriding
Abstraction Expose essentials, hide details Abstract classes and interfaces

Mastering these four pillars gives you the foundation to design clean, flexible, and maintainable object-oriented systems in Java. As you build larger applications, you will combine them constantly — encapsulating state, inheriting shared behavior, relying on polymorphism for flexibility, and using abstraction to manage complexity.