Interview Prep
Interview Questions for OOPs — Encapsulation, Inheritance, Polymorphism, and What Interviewers Actually Want to Hear
OOPs is the most tested CS fundamental in developer interviews. Every Java, C++, Python, and C# interview starts here. The questions are predictable — the four pillars, abstract vs interface, overloading vs overriding. But interviewers want code, not definitions.

OOPs is the foundation of every Java, C++, Python, and C# developer interview — the candidate who writes clean code examples gets the offer.
OOPs Is the First Filter in Developer Interviews
OOPs is the most tested computer science fundamental in developer interviews worldwide. Every Java, C++, Python, and C# interview starts with OOPs. The questions are predictable — the four pillars, abstract vs interface, method overloading vs overriding. Interviewers have asked the same questions for twenty years and they are not going to stop.
But here is the thing most candidates get wrong: interviewers do not want textbook definitions. They want code examples. The candidate who writes a clean inheritance hierarchy on the whiteboard — with proper encapsulation, meaningful method overriding, and a clear explanation of why they chose an abstract class over an interface — gets the job. The candidate who recites "encapsulation is the bundling of data and methods" does not.
This guide covers every OOPs question you will face in a developer interview — with Java code examples, the depth interviewers expect, and the mistakes that get candidates rejected. Whether you are a fresher or a senior developer, these are the questions you need to nail.
The candidate who writes a clean inheritance example on the whiteboard gets the job. The one who recites definitions does not. Every OOPs answer should include code.
The Four Pillars of OOPs
These four questions are asked in every single OOPs interview. Getting them wrong is an instant rejection. Getting them right with clean code examples and real-world reasoning puts you ahead of 80% of candidates.
Q1: Explain Encapsulation with an example
Why they ask: Encapsulation is the most practical pillar — it directly affects how you write production code. Interviewers want to see that you understand why fields should be private and how getters/setters protect data integrity. A BankAccount class is the classic example because it shows real consequences of exposing internal state.
// Encapsulation — hiding internal state, exposing controlled access
public class BankAccount {
private double balance; // private — cannot be accessed directly
private String accountHolder;
public BankAccount(String accountHolder, double initialBalance) {
this.accountHolder = accountHolder;
this.balance = initialBalance;
}
// Controlled access through methods
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Deposit must be positive");
}
balance += amount;
}
public void withdraw(double amount) {
if (amount > balance) {
throw new IllegalArgumentException("Insufficient funds");
}
balance -= amount;
}
}
// Why encapsulation matters:
// Without it: account.balance = -5000; // No validation!
// With it: account.withdraw(5000); // Validates before changing state
// Encapsulation enforces business rules at the class levelQ2: Explain Inheritance with an example
Why they ask: Inheritance is the foundation of code reuse and class hierarchies. Interviewers want to see a parent-child relationship where the child inherits behavior and adds its own. The Animal → Dog example is standard, but explain the "is-a" relationship and when inheritance is appropriate vs composition.
// Inheritance — child class inherits from parent class
public class Animal {
protected String name;
protected int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(name + " is eating");
}
public void sleep() {
System.out.println(name + " is sleeping");
}
}
// Dog "is-a" Animal — inherits eat() and sleep()
public class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age); // calls parent constructor
this.breed = breed;
}
// Dog-specific behavior
public void fetch() {
System.out.println(name + " is fetching the ball");
}
// Override parent behavior
@Override
public void eat() {
System.out.println(name + " is eating dog food");
}
}
// Usage:
// Dog dog = new Dog("Rex", 3, "German Shepherd");
// dog.eat(); // "Rex is eating dog food" (overridden)
// dog.sleep(); // "Rex is sleeping" (inherited from Animal)
// dog.fetch(); // "Rex is fetching the ball" (Dog-specific)Q3: Explain Polymorphism — compile-time vs runtime
Why they ask: Polymorphism is where most candidates stumble. They know the definition but cannot explain the difference between compile-time (method overloading) and runtime (method overriding) polymorphism with code. Show both in one answer and you stand out immediately.
// COMPILE-TIME Polymorphism — Method Overloading
// Same method name, different parameters. Resolved at compile time.
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
}
// Compiler decides which add() to call based on arguments
// RUNTIME Polymorphism — Method Overriding
// Child class overrides parent method. Resolved at runtime.
public class Shape {
public double area() {
return 0;
}
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public class Rectangle extends Shape {
private double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
}
// Runtime polymorphism in action:
// Shape shape = new Circle(5); // parent reference, child object
// shape.area(); // calls Circle's area() — decided at RUNTIME
// Shape shape2 = new Rectangle(4, 6);
// shape2.area(); // calls Rectangle's area() — decided at RUNTIMEQ4: Explain Abstraction with an example
Why they ask: Abstraction is about hiding complexity and exposing only what matters. Interviewers want to see an abstract class with abstract methods that force subclasses to provide implementation. The Shape example works perfectly — Shape defines the contract, Circle and Rectangle provide the details.
// Abstraction — hiding implementation details, showing only essentials
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Abstract methods — no implementation, subclasses MUST override
public abstract double area();
public abstract double perimeter();
// Concrete method — shared by all shapes
public void displayInfo() {
System.out.println("Shape: " + getClass().getSimpleName());
System.out.println("Color: " + color);
System.out.println("Area: " + area());
System.out.println("Perimeter: " + perimeter());
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}
public class Rectangle extends Shape {
private double width, height;
public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
@Override
public double perimeter() {
return 2 * (width + height);
}
}
// The caller does not care HOW area is calculated:
// Shape s = new Circle("Red", 5);
// s.displayInfo(); // Works without knowing Circle's internalsClasses & Objects
These questions test whether you understand the building blocks of OOPs. They sound simple, but interviewers expect precise answers with memory allocation details and constructor chaining examples — not vague explanations.
Q1: What is the difference between a class and an object?
Why they ask: This is the most basic OOPs question and the one where freshers give the weakest answers. Saying "a class is a blueprint and an object is an instance" is correct but insufficient. Interviewers want you to explain memory allocation — the class definition lives in the method area, objects live on the heap, and references live on the stack.
// Class — a blueprint/template (no memory allocated for data)
public class Car {
String brand;
int speed;
public void accelerate() {
speed += 10;
}
}
// Object — an instance of a class (memory allocated on heap)
Car myCar = new Car(); // object 1 — allocated on heap
Car yourCar = new Car(); // object 2 — separate memory on heap
myCar.brand = "Toyota";
yourCar.brand = "Honda";
// Memory layout:
// Stack: myCar (reference) → points to heap object 1
// Stack: yourCar (reference) → points to heap object 2
// Heap: object 1 {brand: "Toyota", speed: 0}
// Heap: object 2 {brand: "Honda", speed: 0}
// Method Area: Car class definition (shared, loaded once)
// Key distinction:
// Class = one definition, loaded once into method area
// Object = many instances, each with own memory on heap
// You can create 1000 Car objects from one Car classQ2: What is a constructor? Types of constructors
Why they ask: Constructors are fundamental to object creation. Interviewers want to see that you know the three types — default, parameterized, and copy — and understand that Java provides a default constructor only if you do not write any constructor yourself.
// 1. DEFAULT Constructor — no parameters
public class Student {
String name;
int age;
// Default constructor (Java provides one if you write none)
public Student() {
this.name = "Unknown";
this.age = 0;
}
}
// 2. PARAMETERIZED Constructor — takes arguments
public class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
// Student s = new Student("Alice", 22);
// 3. COPY Constructor — creates object from another object
public class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// Copy constructor
public Student(Student other) {
this.name = other.name;
this.age = other.age;
}
}
// Student original = new Student("Alice", 22);
// Student copy = new Student(original);
// IMPORTANT: If you define ANY constructor, Java does NOT
// provide the default constructor anymore.
// Student s = new Student(); // COMPILE ERROR if only
// parameterized constructor existsQ3: What is the `this` keyword and when do you use it?
Why they ask: The `this` keyword has multiple uses and interviewers want to see that you know all of them — not just parameter disambiguation. Constructor chaining with `this()` is the answer that impresses interviewers because most candidates forget it.
// Use 1: Disambiguate field vs parameter (most common)
public class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name; // this.name = field, name = parameter
this.salary = salary;
}
}
// Use 2: Constructor chaining with this()
public class Employee {
private String name;
private double salary;
private String department;
public Employee(String name) {
this(name, 50000, "General"); // calls 3-param constructor
}
public Employee(String name, double salary) {
this(name, salary, "General"); // calls 3-param constructor
}
public Employee(String name, double salary, String department) {
this.name = name;
this.salary = salary;
this.department = department;
}
}
// Avoids code duplication — all constructors funnel to one
// Use 3: Passing current object as argument
public class Node {
int value;
Node next;
public void addToList(LinkedList list) {
list.add(this); // passes the current Node object
}
}
// Use 4: Returning current object (method chaining / builder pattern)
public class QueryBuilder {
private String table;
private String condition;
public QueryBuilder from(String table) {
this.table = table;
return this; // returns current object for chaining
}
public QueryBuilder where(String condition) {
this.condition = condition;
return this;
}
}
// new QueryBuilder().from("users").where("age > 25");
Abstract classes, interfaces, and design patterns separate mid-level developers from seniors in OOPs interviews.
Advanced Concepts
These questions separate junior developers from mid-level and senior candidates. Abstract class vs interface is the single most debated OOPs question — and the answer changed significantly with Java 8 default methods. Know the current answer, not the outdated one.
Q1: Abstract class vs Interface — when to use each?
Why they ask: This is the most asked advanced OOPs question. Before Java 8, the answer was simple — abstract classes have method bodies, interfaces do not. After Java 8 introduced default methods, the distinction is more nuanced. Interviewers want to see that you know the modern answer.
// ABSTRACT CLASS — partial implementation, shared state
public abstract class Vehicle {
protected int speed;
protected String fuelType;
public Vehicle(String fuelType) {
this.fuelType = fuelType;
}
// Concrete method — shared behavior
public void start() {
System.out.println("Vehicle starting with " + fuelType);
}
// Abstract method — subclasses must implement
public abstract void drive();
}
// INTERFACE — contract definition, multiple inheritance
public interface Chargeable {
void charge(); // abstract by default
// Java 8: default method with implementation
default void showBatteryStatus() {
System.out.println("Battery status: OK");
}
}
public interface GPSEnabled {
void navigate(String destination);
}
// A class can implement MULTIPLE interfaces but extend ONE class
public class ElectricCar extends Vehicle implements Chargeable, GPSEnabled {
public ElectricCar() {
super("Electric");
}
@Override
public void drive() {
System.out.println("Driving electric car at " + speed + " km/h");
}
@Override
public void charge() {
System.out.println("Charging battery...");
}
@Override
public void navigate(String destination) {
System.out.println("Navigating to " + destination);
}
}
// WHEN TO USE WHICH:
// Abstract class: shared state (fields), constructor needed,
// "is-a" relationship, partial implementation
// Interface: defining a contract, multiple inheritance needed,
// "can-do" capability (Comparable, Serializable, Runnable)Q2: Method overloading vs method overriding — rules for each
Why they ask: Candidates often confuse the rules. Overloading is about different parameter lists in the same class. Overriding is about redefining a parent method in a child class. The rules are strict and interviewers test edge cases — like whether you can override a static method (you cannot — it is method hiding).
// METHOD OVERLOADING — same class, same name, different params
// Compile-time polymorphism (static binding)
public class Printer {
public void print(String text) {
System.out.println("String: " + text);
}
public void print(int number) { // different param type
System.out.println("Integer: " + number);
}
public void print(String text, int copies) { // different param count
for (int i = 0; i < copies; i++) {
System.out.println(text);
}
}
// CANNOT overload by return type alone — compile error
// public int print(String text) { return 0; } // ERROR
}
// METHOD OVERRIDING — child class redefines parent method
// Runtime polymorphism (dynamic binding)
public class Animal {
public String speak() {
return "...";
}
}
public class Dog extends Animal {
@Override
public String speak() { // same name, same params, same return
return "Woof!";
}
}
// OVERRIDING RULES:
// 1. Same method signature (name + parameters)
// 2. Return type must be same or covariant (subtype)
// 3. Access modifier cannot be MORE restrictive
// (parent is public → child cannot be private)
// 4. Cannot override static methods (that is method HIDING)
// 5. Cannot override final methods
// 6. Cannot override private methods (not inherited)
// 7. @Override annotation is optional but ALWAYS use itQ3: What is the diamond problem in multiple inheritance?
Why they ask: The diamond problem explains why Java does not support multiple class inheritance. Interviewers want to see that you understand the ambiguity it creates and how Java solves it with interfaces. With Java 8 default methods, the diamond problem can now occur with interfaces too — knowing this shows depth.
// THE DIAMOND PROBLEM:
//
// Animal
// / \
// Flyer Swimmer
// \ /
// FlyingFish
//
// If Animal has eat(), and both Flyer and Swimmer override eat(),
// which eat() does FlyingFish inherit? AMBIGUOUS.
// Java's solution: No multiple class inheritance.
// Use interfaces instead.
public interface Flyer {
default void move() {
System.out.println("Flying through the air");
}
}
public interface Swimmer {
default void move() {
System.out.println("Swimming through water");
}
}
// Diamond problem with Java 8 default methods:
// Both interfaces have move() — compiler forces you to resolve it
public class FlyingFish implements Flyer, Swimmer {
@Override
public void move() {
// Option 1: Provide your own implementation
System.out.println("Gliding above water");
// Option 2: Explicitly choose one interface's default
// Flyer.super.move();
// Swimmer.super.move();
}
}
// Key points for the interview:
// 1. Java does NOT support multiple class inheritance
// 2. Java DOES support multiple interface implementation
// 3. If two interfaces have same default method, class MUST override
// 4. C++ supports multiple inheritance (and has the diamond problem)
// 5. Python uses MRO (Method Resolution Order) to resolve itQ4: What are access modifiers? Explain visibility
Why they ask: Access modifiers control encapsulation. Interviewers want to see that you know all four levels and can explain the difference between protected and default (package-private) — this is where most candidates get confused.
// ACCESS MODIFIERS — Visibility Table
//
// Modifier | Same Class | Same Package | Subclass | Everywhere
// -------------|------------|--------------|----------|----------
// public | YES | YES | YES | YES
// protected | YES | YES | YES | NO
// default | YES | YES | NO* | NO
// private | YES | NO | NO | NO
//
// *default access: subclass can access ONLY if in same package
public class Employee {
public String name; // accessible everywhere
protected String department; // accessible in subclass + same package
String team; // default — same package only
private double salary; // this class only
// Practical usage:
// public: API methods that other classes call
// protected: methods subclasses need to override
// default: internal helper classes in the same package
// private: internal state that should never leak
}
// Common interview follow-up:
// "Can a class be private?"
// Top-level class: NO (only public or default)
// Inner class: YES (private inner class is valid)
public class Outer {
private class Inner { // valid — only Outer can use Inner
void doSomething() { }
}
}Practice OOPs Questions With AI Mock Interviews
Reading OOPs questions is not the same as explaining them under pressure. Practice with timed mock interviews that test your ability to write code on the spot, explain design decisions, and handle follow-up questions interviewers throw at you.
TRY INTERVIEW PRACTICE →Design Patterns
Design pattern questions are asked at mid-level and senior interviews. You do not need to know all 23 GoF patterns — but Singleton, Factory, and Observer come up repeatedly. Interviewers want working code, not UML diagrams.
Q1: What is the Singleton pattern? Write a thread-safe one
Why they ask: Singleton is the most asked design pattern question. The basic version is easy — but interviewers want the thread-safe version. If you write a naive Singleton without synchronization, the follow-up question is always "what happens with multiple threads?" Write the double-checked locking version and you skip that trap entirely.
// Singleton — only ONE instance of the class exists
// THREAD-SAFE Singleton with double-checked locking
public class DatabaseConnection {
private static volatile DatabaseConnection instance;
private String connectionUrl;
// Private constructor — prevents new DatabaseConnection()
private DatabaseConnection() {
this.connectionUrl = "jdbc:mysql://localhost:3306/mydb";
System.out.println("Database connection created");
}
public static DatabaseConnection getInstance() {
if (instance == null) { // First check (no lock)
synchronized (DatabaseConnection.class) {
if (instance == null) { // Second check (with lock)
instance = new DatabaseConnection();
}
}
}
return instance;
}
public void query(String sql) {
System.out.println("Executing: " + sql);
}
}
// Usage:
// DatabaseConnection db1 = DatabaseConnection.getInstance();
// DatabaseConnection db2 = DatabaseConnection.getInstance();
// db1 == db2 → true (same instance)
// Why volatile? Without it, a thread might see a partially
// constructed object due to instruction reordering.
// SIMPLEST thread-safe approach — Bill Pugh Singleton:
public class Singleton {
private Singleton() { }
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE; // loaded lazily, thread-safe by JVM
}
}Q2: What is the Factory pattern? When would you use it?
Why they ask: Factory pattern decouples object creation from usage. Interviewers want to see that you understand why `new ConcreteClass()` scattered everywhere is a problem — and how a factory centralizes creation logic so adding new types does not require changing client code.
// Factory Pattern — centralizes object creation
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
@Override
public void send(String message) {
System.out.println("Email: " + message);
}
}
public class SMSNotification implements Notification {
@Override
public void send(String message) {
System.out.println("SMS: " + message);
}
}
public class PushNotification implements Notification {
@Override
public void send(String message) {
System.out.println("Push: " + message);
}
}
// Factory — creates the right object based on type
public class NotificationFactory {
public static Notification create(String type) {
switch (type.toLowerCase()) {
case "email": return new EmailNotification();
case "sms": return new SMSNotification();
case "push": return new PushNotification();
default: throw new IllegalArgumentException(
"Unknown notification type: " + type
);
}
}
}
// Usage — client code never uses "new" directly:
// Notification n = NotificationFactory.create("email");
// n.send("Your order has shipped");
// Why Factory matters:
// 1. Adding WhatsAppNotification = change factory only
// 2. Client code stays unchanged
// 3. Easy to test — mock the factory
// 4. Single place to add logging, caching, validationQ3: What is the Observer pattern? Give a real-world example
Why they ask: Observer pattern is everywhere — event listeners in UI frameworks, pub/sub messaging, notification systems. Interviewers want to see that you understand the one-to-many dependency where changing one object notifies all dependents automatically.
// Observer Pattern — one-to-many notification
import java.util.ArrayList;
import java.util.List;
// Observer interface
public interface StockObserver {
void update(String stockName, double price);
}
// Subject — the thing being observed
public class StockMarket {
private List<StockObserver> observers = new ArrayList<>();
private String stockName;
private double price;
public void addObserver(StockObserver observer) {
observers.add(observer);
}
public void removeObserver(StockObserver observer) {
observers.remove(observer);
}
public void setPrice(String stockName, double price) {
this.stockName = stockName;
this.price = price;
notifyObservers(); // automatically notify all observers
}
private void notifyObservers() {
for (StockObserver observer : observers) {
observer.update(stockName, price);
}
}
}
// Concrete observers
public class MobileApp implements StockObserver {
@Override
public void update(String stockName, double price) {
System.out.println("Mobile alert: " + stockName + " = $" + price);
}
}
public class EmailAlert implements StockObserver {
@Override
public void update(String stockName, double price) {
if (price > 1000) {
System.out.println("Email: " + stockName + " crossed $1000!");
}
}
}
// Usage:
// StockMarket market = new StockMarket();
// market.addObserver(new MobileApp());
// market.addObserver(new EmailAlert());
// market.setPrice("AAPL", 1050);
// → Mobile alert: AAPL = $1050.0
// → Email: AAPL crossed $1000!
// Real-world examples: event listeners, message queues,
// React state updates, push notificationsPractical Code Questions
These are the questions where interviewers hand you a marker and say "design this on the whiteboard." They test whether you can translate OOPs concepts into actual class hierarchies. The parking lot question alone appears in interviews at Amazon, Google, Microsoft, and every major tech company.
Q1: Design a parking lot system using OOPs
Why they ask: This is the most classic OOPs design question. It tests inheritance (Vehicle → Car, Truck), encapsulation (ParkingSpot manages its own state), polymorphism (different vehicle types parked differently), and composition (ParkingLot has ParkingSpots). Start with the class hierarchy, then add methods.
// Parking Lot System — OOPs Design
public abstract class Vehicle {
private String licensePlate;
private VehicleSize size;
public Vehicle(String licensePlate, VehicleSize size) {
this.licensePlate = licensePlate;
this.size = size;
}
public VehicleSize getSize() { return size; }
public String getLicensePlate() { return licensePlate; }
}
public enum VehicleSize { SMALL, MEDIUM, LARGE }
public class Car extends Vehicle {
public Car(String licensePlate) {
super(licensePlate, VehicleSize.MEDIUM);
}
}
public class Motorcycle extends Vehicle {
public Motorcycle(String licensePlate) {
super(licensePlate, VehicleSize.SMALL);
}
}
public class Truck extends Vehicle {
public Truck(String licensePlate) {
super(licensePlate, VehicleSize.LARGE);
}
}
public class ParkingSpot {
private int spotNumber;
private VehicleSize size;
private Vehicle currentVehicle;
public ParkingSpot(int spotNumber, VehicleSize size) {
this.spotNumber = spotNumber;
this.size = size;
}
public boolean canFit(Vehicle vehicle) {
return currentVehicle == null
&& vehicle.getSize().ordinal() <= size.ordinal();
}
public boolean park(Vehicle vehicle) {
if (!canFit(vehicle)) return false;
currentVehicle = vehicle;
return true;
}
public Vehicle removeVehicle() {
Vehicle v = currentVehicle;
currentVehicle = null;
return v;
}
public boolean isAvailable() { return currentVehicle == null; }
}
public class ParkingLot {
private List<ParkingSpot> spots;
public ParkingLot(int small, int medium, int large) {
spots = new ArrayList<>();
int id = 1;
for (int i = 0; i < small; i++) spots.add(new ParkingSpot(id++, VehicleSize.SMALL));
for (int i = 0; i < medium; i++) spots.add(new ParkingSpot(id++, VehicleSize.MEDIUM));
for (int i = 0; i < large; i++) spots.add(new ParkingSpot(id++, VehicleSize.LARGE));
}
public boolean parkVehicle(Vehicle vehicle) {
for (ParkingSpot spot : spots) {
if (spot.park(vehicle)) return true;
}
return false; // lot is full for this vehicle size
}
public long getAvailableSpots() {
return spots.stream().filter(ParkingSpot::isAvailable).count();
}
}Q2: Implement a simple library management system
Why they ask: This tests your ability to model real-world entities as classes with proper relationships. Book, Member, and Library are the core classes. Interviewers look for encapsulation (Book manages its own availability), composition (Library has Books and Members), and clean method design.
// Library Management System
public class Book {
private String isbn;
private String title;
private String author;
private boolean isAvailable;
public Book(String isbn, String title, String author) {
this.isbn = isbn;
this.title = title;
this.author = author;
this.isAvailable = true;
}
public boolean isAvailable() { return isAvailable; }
public void checkout() { isAvailable = false; }
public void returnBook() { isAvailable = true; }
public String getIsbn() { return isbn; }
public String getTitle() { return title; }
}
public class Member {
private String memberId;
private String name;
private List<Book> borrowedBooks;
private static final int MAX_BOOKS = 3;
public Member(String memberId, String name) {
this.memberId = memberId;
this.name = name;
this.borrowedBooks = new ArrayList<>();
}
public boolean canBorrow() {
return borrowedBooks.size() < MAX_BOOKS;
}
public void borrow(Book book) {
borrowedBooks.add(book);
}
public void returnBook(Book book) {
borrowedBooks.remove(book);
}
}
public class Library {
private List<Book> catalog;
private List<Member> members;
public Library() {
this.catalog = new ArrayList<>();
this.members = new ArrayList<>();
}
public void addBook(Book book) { catalog.add(book); }
public void registerMember(Member member) { members.add(member); }
public boolean issueBook(String isbn, Member member) {
if (!member.canBorrow()) return false;
for (Book book : catalog) {
if (book.getIsbn().equals(isbn) && book.isAvailable()) {
book.checkout();
member.borrow(book);
return true;
}
}
return false; // book not found or not available
}
public void returnBook(String isbn, Member member) {
for (Book book : catalog) {
if (book.getIsbn().equals(isbn)) {
book.returnBook();
member.returnBook(book);
break;
}
}
}
public List<Book> searchByTitle(String keyword) {
return catalog.stream()
.filter(b -> b.getTitle().toLowerCase()
.contains(keyword.toLowerCase()))
.collect(Collectors.toList());
}
}Q3: What is wrong with this code? (Liskov Substitution violation)
Why they ask: "Find the bug" questions test your understanding of OOPs principles in practice. The classic example is Rectangle/Square — Square extends Rectangle but breaks the parent's contract. This violates the Liskov Substitution Principle: a subclass should be usable wherever the parent is used without breaking behavior.
// BROKEN CODE — Liskov Substitution Principle violation
public class Rectangle {
protected int width;
protected int height;
public void setWidth(int width) { this.width = width; }
public void setHeight(int height) { this.height = height; }
public int getArea() { return width * height; }
}
// Square "is-a" Rectangle? Mathematically yes. In OOPs? NO.
public class Square extends Rectangle {
@Override
public void setWidth(int width) {
this.width = width;
this.height = width; // forces height = width
}
@Override
public void setHeight(int height) {
this.width = height; // forces width = height
this.height = height;
}
}
// THE PROBLEM:
public void resize(Rectangle r) {
r.setWidth(5);
r.setHeight(10);
assert r.getArea() == 50; // FAILS for Square!
// Square: setHeight(10) sets both to 10 → area = 100
}
// This breaks Liskov Substitution:
// Code that works with Rectangle breaks with Square
// Square cannot be substituted for Rectangle safely
// THE FIX — use composition or separate hierarchy:
public interface Shape {
int getArea();
}
public class Rectangle implements Shape {
private final int width, height;
public Rectangle(int w, int h) { width = w; height = h; }
public int getArea() { return width * height; }
}
public class Square implements Shape {
private final int side;
public Square(int side) { this.side = side; }
public int getArea() { return side * side; }
}
// Now Rectangle and Square are siblings, not parent-child
// No LSP violation — each implements Shape independentlyHow to Prepare — By Experience Level
The depth of OOPs knowledge tested varies dramatically by experience level. A fresher who can write the four pillars with code examples is impressive. A senior developer who cannot explain SOLID principles or design pattern trade-offs is a red flag.
Freshers (0-1 years)
Preparation time: 1 week. Master the four pillars with code examples you can write from memory. Practice writing classes on paper — not on an IDE. Know constructors, access modifiers, `this` and `super` keywords, and the difference between abstract class and interface. Be able to write a simple class hierarchy (Animal → Dog, Shape → Circle) in under 5 minutes. Every fresher interview starts with "explain the four pillars of OOPs" — your answer should include code, not just definitions.
Mid-Level (2-5 years)
Preparation time: 2 weeks. Everything freshers need, plus design patterns (Singleton, Factory, Observer, Strategy), SOLID principles with code examples, and real system design using OOPs. You should be able to design a parking lot or library system on the whiteboard in 15 minutes. Know when to use inheritance vs composition, abstract class vs interface (with Java 8 nuances), and explain the diamond problem. Interviewers at this level test judgment — "why did you choose an interface here instead of an abstract class?"
Senior (5+ years)
Preparation time: 1 week review. At this level, OOPs questions are embedded in system design and code review scenarios. You should explain trade-offs — when inheritance creates tight coupling and composition is better, when the Singleton pattern becomes an anti-pattern, why deep inheritance hierarchies are a code smell. Be ready for "review this code" questions where you identify LSP violations, God classes, or leaky abstractions. Know architectural patterns (MVC, Repository, Dependency Injection) and how they apply OOPs principles at scale.
Practice With Real Interview Simulations
Reading OOPs questions is not the same as answering them under pressure. Practice with timed mock interviews that test your ability to write code on the spot, explain design decisions, and handle the follow-up questions that trip up most candidates.
TRY INTERVIEW PRACTICE →OOPs interviews are predictable. The four pillars, abstract vs interface, design patterns, and a whiteboard coding question. Prepare code examples for each, practice writing them without an IDE, and you will clear the OOPs round at any company.
OOPs is the most tested CS fundamental in developer interviews worldwide. The questions have not changed in twenty years — four pillars, abstract vs interface, overloading vs overriding, and a design question. The candidates who succeed are the ones who write code, not recite definitions. Master the four pillars with examples you can write from memory, learn three design patterns deeply, and practice designing class hierarchies on paper. Every code example you write in practice is one less you will struggle with on the whiteboard.
Prepare for Your OOPs Interview
Practice with AI-powered mock interviews, get your resume ATS-ready, and walk into your next developer interview with confidence.
Free · AI-powered · Instant feedback
Related Reading
Interview Prep
Interview Coding Questions — Java
Data structures, algorithms, and coding problems asked in Java interviews
15 min read
Interview Prep
Interview Questions — Java 8
Streams, lambdas, functional interfaces, and Optional — what interviewers test
12 min read
Resume Guide
Software Engineer Resume
Build a resume that highlights your OOPs and system design skills
10 min read