Difficulty: Beginner
What are the four pillars of Object-Oriented Programming? Explain each briefly with a real-world analogy.
This is the question that opens almost every campus placement technical round, so let's make sure your answer is crisp, structured, and has an analogy for each pillar so it sticks in the interviewer's mind.
The reason OOP exists is to manage complexity. Once programs grow beyond a few thousand lines, procedural code with global data becomes fragile, because any function can touch any data. OOP organises code around objects that combine data with the operations on that data, and the four pillars are the principles that make this organisation work.
Encapsulation is about bundling data and methods together and restricting direct access to the internals. Think of a medicine capsule: the powder inside is protected, and you interact with it only through the outer shell. In code, you make fields private and expose controlled getters, setters, or behaviour methods, so the object can protect its own invariants, for example never allowing a negative account balance.
Abstraction is about exposing only what is necessary and hiding how it works. When you drive a car you use the steering wheel, accelerator, and brake without knowing anything about the fuel injection system. In code, abstraction is achieved through abstract classes and interfaces, where callers depend on what an object does rather than how it does it. A quick way to remember the difference: abstraction hides complexity at the design level, encapsulation hides data at the implementation level.
Inheritance lets a class acquire the fields and methods of another class, modelling an is-a relationship. A Dog is an Animal, so it reuses eat() and sleep() and adds bark(). It promotes code reuse and gives you a hierarchy, but it also creates tight coupling between parent and child, which is why experienced developers say to favour composition when the relationship is not truly is-a.
Polymorphism means one interface, many forms. The same call behaves differently depending on the actual object. Think of pressing play: on a music player it plays a song, on a video player it plays a movie. It comes in two flavours: compile-time polymorphism (method overloading) and run-time polymorphism (method overriding with dynamic dispatch).
How do they work together? In the example below, the abstract Shape hides how areas are computed (abstraction), each subclass keeps its dimensions private (encapsulation), Circle and Rect reuse the Shape contract (inheritance), and the loop calls area() on a Shape reference while the JVM picks the right implementation at run time (polymorphism).
A good closing line for the interview: the pillars are not four separate features, they reinforce each other. Encapsulation protects state, abstraction defines contracts, inheritance shares structure, and polymorphism lets you extend behaviour without changing the caller. Mention that some books treat only three pillars (leaving out abstraction or treating it as part of encapsulation), so be ready if the interviewer has a different count in mind.
abstract class Shape { // abstraction
abstract double area();
}
class Circle extends Shape { // inheritance
private final double r; // encapsulation
Circle(double r) { this.r = r; }
@Override double area() { return Math.PI * r * r; }
}
class Rect extends Shape {
private final double w, h;
Rect(double w, double h) { this.w = w; this.h = h; }
@Override double area() { return w * h; }
}
public class Pillars {
public static void main(String[] args) {
Shape[] shapes = { new Circle(1), new Rect(2, 3) };
for (Shape s : shapes) { // polymorphism
System.out.printf("%.2f%n", s.area());
}
}
}
The loop only knows about Shape, yet each call is dispatched to the correct subclass at run time.
encapsulation, abstraction, inheritance, polymorphism