Toolmingo
Guides19 min read

50 OOP Interview Questions and Answers (2025)

Top object-oriented programming interview questions with clear answers and code examples — covering classes, inheritance, polymorphism, encapsulation, abstraction, SOLID principles, and design patterns.

Object-oriented programming (OOP) questions appear in almost every developer interview — from junior to staff level. This guide covers the 50 most common OOP interview questions with concise answers, code examples in multiple languages, and comparison tables.

Quick reference

Topic Core concepts
Four pillars Encapsulation, Abstraction, Inheritance, Polymorphism
Class vs Object Blueprint vs instance
Polymorphism types Compile-time (overloading) vs runtime (overriding)
SOLID principles SRP, OCP, LSP, ISP, DIP
Relationships Association, Aggregation, Composition, Inheritance
Design patterns Creational, Structural, Behavioural

Core Concepts

1. What are the four pillars of OOP?

Pillar One-line definition
Encapsulation Bundle data + methods; hide internal state behind a public interface
Abstraction Expose only what callers need; hide complexity
Inheritance A class inherits properties and behaviour from a parent class
Polymorphism One interface, many implementations; objects of different types respond to the same message

2. What is the difference between a class and an object?

A class is a blueprint or template that defines structure and behaviour. An object is a concrete instance of that class created at runtime with its own memory.

class Car:               # class (blueprint)
    def __init__(self, make):
        self.make = make  # instance attribute

toyota = Car("Toyota")   # object (instance)
honda  = Car("Honda")    # another object

Every object has its own copy of instance attributes but shares class-level methods.

3. What is encapsulation? How do you achieve it?

Encapsulation bundles data (attributes) and operations (methods) into a single unit and restricts direct access to internal state. You achieve it through access modifiers:

Modifier Java/C# Python convention
Public public name
Protected protected _name
Private private __name
public class BankAccount {
    private double balance;           // hidden

    public double getBalance() {      // controlled access
        return balance;
    }
    public void deposit(double amount) {
        if (amount > 0) balance += amount;
    }
}

4. What is abstraction? How does it differ from encapsulation?

Abstraction is about what an object does — exposing only the relevant interface to callers. Encapsulation is about how it does it — hiding the implementation.

from abc import ABC, abstractmethod

class Shape(ABC):          # abstraction: defines what every shape must do
    @abstractmethod
    def area(self) -> float: ...

class Circle(Shape):       # concrete class provides the how
    def __init__(self, r):
        self.r = r
    def area(self):
        return 3.14159 * self.r ** 2

Callers only care that shape.area() exists — they don't care about the formula.

5. What is inheritance? What are its types?

Inheritance lets a child class acquire properties and methods from a parent class, enabling code reuse and establishing an "is-a" relationship.

Type Description Support
Single One parent All OOP languages
Multilevel Chain: A → B → C All OOP languages
Hierarchical Multiple children from one parent All OOP languages
Multiple One child, multiple parents Python, C++ (not Java)
Hybrid Combination of the above Python, C++
class Animal:
    def speak(self): return "..."

class Dog(Animal):          # single inheritance
    def speak(self): return "Woof"

class GoldenRetriever(Dog): # multilevel
    pass

6. What is polymorphism? What are its types?

Polymorphism allows objects of different types to be treated through a shared interface.

Type Also called When resolved Mechanism
Compile-time Static / overloading Compile time Method overloading
Runtime Dynamic / overriding Run time Method overriding
// Compile-time polymorphism (overloading)
class Math {
    int add(int a, int b)       { return a + b; }
    double add(double a, double b) { return a + b; }
}

// Runtime polymorphism (overriding)
class Animal  { String sound() { return "..."; } }
class Cat extends Animal { String sound() { return "Meow"; } }

Animal a = new Cat();
System.out.println(a.sound()); // "Meow" — decided at runtime

7. What is method overloading vs method overriding?

Overloading Overriding
Where Same class Child class
Signature Different parameters Same signature
Resolution Compile time Runtime
Inheritance needed? No Yes
Return type Can differ (in some languages) Must be same (or covariant)

8. What is a constructor? Types of constructors?

A constructor is a special method called when an object is created. It initialises the object's state.

Type Description
Default No parameters; provided automatically if none defined
Parameterised Takes arguments to initialise fields
Copy Creates a new object from an existing one (C++)
Static / class Called once per class (Python __init_subclass__, Java static blocks)
class Point:
    def __init__(self, x=0, y=0):   # parameterised (default values → also acts as default)
        self.x = x
        self.y = y

p1 = Point()        # default-like
p2 = Point(3, 4)    # parameterised

9. What is a destructor?

A destructor is called when an object is garbage collected or goes out of scope. It releases resources held by the object.

class FileHandler:
    def __init__(self, path):
        self.f = open(path)

    def __del__(self):            # destructor
        self.f.close()

Prefer context managers (with statement / IDisposable in C#) over explicit destructors — they are more predictable.

10. What is the difference between this and super?

Keyword Refers to Common use
this Current object Disambiguate fields, chain constructors
super Parent class Call parent constructor, access overridden methods
class Vehicle {
    String type;
    Vehicle(String type) { this.type = type; }
    String info() { return "Vehicle: " + type; }
}

class Car extends Vehicle {
    int doors;
    Car(String type, int doors) {
        super(type);          // parent constructor
        this.doors = doors;   // current object
    }
    String info() {
        return super.info() + " | Doors: " + doors;
    }
}

Inheritance & Relationships

11. What is the difference between inheritance and composition?

Inheritance ("is-a") Composition ("has-a")
Relationship Dog is an Animal Car has an Engine
Coupling Tight (child depends on parent) Loose (depend on interface)
Flexibility Harder to change hierarchy Swap implementations easily
Code reuse Implicit via hierarchy Explicit via delegation

Prefer composition over inheritance (GoF principle) unless a genuine "is-a" relationship exists.

# Composition
class Engine:
    def start(self): return "vroom"

class Car:
    def __init__(self):
        self._engine = Engine()     # has-a
    def start(self):
        return self._engine.start()

12. What is association, aggregation, and composition?

Relationship Lifecycle dependency Example
Association Independent Teacher and Student
Aggregation Child can exist without parent Department and Employee
Composition Child cannot exist without parent House and Room

13. What is multiple inheritance? Why does Java not support it?

Multiple inheritance lets a class inherit from more than one parent. Java excludes it for classes to avoid the Diamond Problem: if classes B and C both inherit from A and define method(), a class D inheriting from both B and C is ambiguous about which method() to use.

Java solves this via interfaces (a class can implement many interfaces).

# Python handles the Diamond Problem via MRO (Method Resolution Order)
class A:
    def hello(self): return "A"

class B(A):
    def hello(self): return "B"

class C(A):
    def hello(self): return "C"

class D(B, C): pass   # MRO: D → B → C → A

print(D.__mro__)       # shows resolution order
print(D().hello())     # "B"

14. What is an abstract class vs an interface?

Abstract class Interface
Instantiate? No No
State (fields) Yes No (Java); Yes (Python ABC)
Constructor Yes No
Multiple inheritance No (Java) Yes (implement many)
Default method Yes Yes (Java 8+, Python via ABC)
Use when Share common base code Define a contract
abstract class Shape {
    String colour;                    // state allowed
    abstract double area();           // subclasses must implement
    String describe() { return "I am " + colour; } // concrete method
}

interface Drawable {
    void draw();                      // contract only (Java < 8)
    default void printInfo() { System.out.println("Drawable"); }
}

15. Can you instantiate an abstract class?

No. An abstract class cannot be instantiated directly. You must subclass it and implement all abstract methods.

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self): ...

a = Animal()    # TypeError: Can't instantiate abstract class

Access & Modifiers

16. What are access modifiers?

Access modifiers control the visibility of class members.

Modifier Java Accessible from
public public Everywhere
protected protected Same package + subclasses
Package-private (no modifier) Same package only
private private Same class only

17. What is a static member?

A static member belongs to the class, not to any instance. All instances share the same static field. Static methods can be called without creating an object.

class Counter {
    static int count = 0;    // shared across all instances
    Counter() { count++; }
    static int getCount() { return count; }
}

Counter a = new Counter();
Counter b = new Counter();
System.out.println(Counter.getCount()); // 2

18. What is a final keyword (Java)?

Applied to Effect
final variable Cannot be reassigned (constant)
final method Cannot be overridden in subclasses
final class Cannot be subclassed (e.g., String)

19. What is method hiding vs method overriding?

  • Method overriding: runtime polymorphism — the child method is invoked based on the actual runtime type.
  • Method hiding: when a child class defines a static method with the same signature as a parent's static method — resolved at compile time based on the reference type, not runtime type.

20. What is covariant return type?

An overriding method can return a subtype of the return type declared in the parent. This is covariant return.

class Animal { Animal create() { return new Animal(); } }
class Dog extends Animal {
    @Override
    Dog create() { return new Dog(); } // Dog is subtype of Animal — OK
}

Polymorphism Deep Dive

21. What is dynamic dispatch?

Dynamic dispatch (also called virtual dispatch) is the mechanism by which the runtime determines which overridden method to call based on the actual object type, not the reference type.

Animal a = new Dog();  // reference type: Animal; runtime type: Dog
a.sound();             // dynamic dispatch → calls Dog.sound()

In C++, you need virtual to enable dynamic dispatch. In Java and Python, all instance methods are virtual by default.

22. What is duck typing?

Duck typing is a polymorphism concept from dynamic languages: "If it walks like a duck and quacks like a duck, it's a duck." The type of an object is determined by its capabilities (methods it has), not its class hierarchy.

class Dog:
    def speak(self): return "Woof"

class Robot:
    def speak(self): return "Beep"

def make_it_speak(thing):
    print(thing.speak())         # no type check needed

make_it_speak(Dog())             # "Woof"
make_it_speak(Robot())           # "Beep"

23. What is operator overloading?

Operator overloading lets you define custom behaviour for operators (+, ==, <, etc.) on your own objects.

class Vector:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __add__(self, other):         # overloads +
        return Vector(self.x + other.x, self.y + other.y)

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

v = Vector(1, 2) + Vector(3, 4)      # Vector(4, 6)

Java does not support operator overloading (except + for String).

24. What is upcasting and downcasting?

Direction Safety Example
Upcasting Child → Parent Always safe (implicit) Animal a = new Dog()
Downcasting Parent → Child May throw ClassCastException Dog d = (Dog) a

Always check with instanceof before downcasting in Java, or isinstance() in Python.

25. What is an interface default method? Why was it added?

Java 8 added default methods to interfaces to allow adding new methods without breaking existing implementations.

interface Logger {
    void log(String msg);
    default void logInfo(String msg) {   // default — implementations not forced to override
        log("[INFO] " + msg);
    }
}

Design & Best Practices

26. What are the SOLID principles?

Letter Principle One-line rule
S Single Responsibility A class should have one reason to change
O Open/Closed Open for extension, closed for modification
L Liskov Substitution Subtypes must be substitutable for their base type
I Interface Segregation No client should be forced to depend on methods it doesn't use
D Dependency Inversion Depend on abstractions, not concretions

27. What is the Single Responsibility Principle (SRP)?

A class should have one reason to change — it should do one job well.

# Violation: one class handles data + formatting + persistence
class Report:
    def calculate(self): ...
    def format_html(self): ...
    def save_to_db(self): ...

# SRP: split responsibilities
class ReportCalculator: ...
class ReportFormatter: ...
class ReportRepository: ...

28. What is the Open/Closed Principle (OCP)?

Classes should be open for extension but closed for modification. Add behaviour by adding new code (subclass / new implementation), not editing existing, tested code.

# Violation: add a new shape → edit existing method
def area(shape):
    if shape.type == "circle": ...
    if shape.type == "square": ...   # keep modifying

# OCP: use polymorphism
class Shape(ABC):
    @abstractmethod
    def area(self) -> float: ...

class Circle(Shape): ...
class Triangle(Shape): ...   # extend by adding class, no edits to others

29. What is the Liskov Substitution Principle (LSP)?

Objects of a subclass should be replaceable with objects of their superclass without altering the correctness of the program.

// Violation: Square forces both sides equal, breaking Rectangle behaviour
class Rectangle { setWidth(w); setHeight(h); }
class Square extends Rectangle {
    setWidth(w) { this.w = this.h = w; }   // breaks LSP
}

// Fix: don't extend Rectangle; use a common interface
interface Shape { double area(); }
class Rectangle implements Shape { ... }
class Square    implements Shape { ... }

30. What is the Dependency Inversion Principle (DIP)?

High-level modules should not depend on low-level modules. Both should depend on abstractions.

# Violation: OrderService directly depends on MySQLDatabase
class OrderService:
    def __init__(self):
        self.db = MySQLDatabase()   # concrete dependency

# DIP: depend on abstraction
class OrderService:
    def __init__(self, db: DatabaseInterface):
        self.db = db                # inject any implementation

Memory & Object Lifecycle

31. What is the difference between shallow copy and deep copy?

Shallow copy Deep copy
Copies Object + references to children Object + all children recursively
Nested objects Shared Independent
Python copy.copy() copy.deepcopy()
import copy

original = {"a": [1, 2, 3]}
shallow  = copy.copy(original)
deep     = copy.deepcopy(original)

original["a"].append(4)
print(shallow["a"])   # [1, 2, 3, 4]  — shared reference
print(deep["a"])      # [1, 2, 3]     — independent

32. What is garbage collection?

Garbage collection (GC) automatically reclaims memory occupied by objects that are no longer reachable. Common algorithms:

Algorithm How it works
Reference counting CPython default; reclaims when count hits 0
Mark-and-sweep Trace live objects from roots; sweep unmarked (Java GC)
Generational GC Divides objects by age; most objects die young (Java, Python)

33. What is object pooling?

Object pooling pre-creates a set of objects and reuses them instead of creating/destroying on every request. Reduces GC pressure and allocation cost (e.g., thread pools, database connection pools).

34. What is the difference between stack and heap memory?

Stack Heap
Stores Local variables, method frames Objects, dynamic allocations
Managed by CPU automatically GC or developer
Speed Very fast Slower
Size Limited (causes StackOverflow) Large
Thread safety Per-thread (safe) Shared (needs synchronisation)

Design Patterns

35. What are the three categories of design patterns?

Category Purpose Examples
Creational Object creation mechanisms Singleton, Factory, Builder, Prototype
Structural Object composition Adapter, Decorator, Facade, Proxy
Behavioural Object communication Observer, Strategy, Command, Iterator

36. What is the Singleton pattern? What are its drawbacks?

Singleton ensures only one instance of a class exists and provides a global access point.

class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

Drawbacks: global state makes testing hard; hides dependencies; not thread-safe without locks; violates SRP.

37. What is the Factory pattern?

Factory pattern provides an interface for creating objects without specifying their exact class.

class AnimalFactory:
    @staticmethod
    def create(kind: str):
        if kind == "dog": return Dog()
        if kind == "cat": return Cat()
        raise ValueError(f"Unknown animal: {kind}")

a = AnimalFactory.create("dog")

38. What is the Observer pattern?

Observer defines a one-to-many dependency: when one object (subject) changes state, all dependents (observers) are notified automatically.

class EventEmitter:
    def __init__(self):
        self._listeners = []

    def subscribe(self, fn):
        self._listeners.append(fn)

    def emit(self, data):
        for fn in self._listeners:
            fn(data)

emitter = EventEmitter()
emitter.subscribe(lambda d: print("Listener 1:", d))
emitter.emit("click")

39. What is the Decorator pattern?

Decorator adds behaviour to objects dynamically without modifying their class.

def bold(fn):
    def wrapper(*args, **kwargs):
        return "<b>" + fn(*args, **kwargs) + "</b>"
    return wrapper

@bold
def greet(name): return f"Hello, {name}"

print(greet("Alice"))   # <b>Hello, Alice</b>

40. What is the Strategy pattern?

Strategy defines a family of algorithms, encapsulates each one, and makes them interchangeable.

class Sorter:
    def __init__(self, strategy):
        self._strategy = strategy

    def sort(self, data):
        return self._strategy(data)

quick_sorter = Sorter(sorted)              # built-in
custom_sorter = Sorter(lambda d: d[::-1]) # reverse

Advanced OOP Concepts

41. What is coupling and cohesion?

Concept Definition Goal
Coupling Degree of dependency between modules Low coupling
Cohesion Degree to which elements of a module belong together High cohesion

High cohesion + low coupling = maintainable, testable code.

42. What is the Law of Demeter?

Also called the "Principle of Least Knowledge": a method should only call methods on:

  1. Itself
  2. Its parameters
  3. Objects it created
  4. Its direct component objects

Avoid train wrecks: a.getB().getC().doSomething() — each step adds coupling.

43. What is the difference between early binding and late binding?

Early binding (static) Late binding (dynamic)
Resolved at Compile time Runtime
Example Overloaded methods Overridden virtual methods
Performance Faster Slight overhead

44. What is method chaining / fluent interface?

Method chaining returns this from each method so calls can be chained.

class QueryBuilder:
    def __init__(self):
        self._parts = []

    def select(self, cols):
        self._parts.append(f"SELECT {cols}")
        return self

    def where(self, cond):
        self._parts.append(f"WHERE {cond}")
        return self

    def build(self):
        return " ".join(self._parts)

sql = QueryBuilder().select("*").where("id = 1").build()

45. What is the Template Method pattern?

Template Method defines the skeleton of an algorithm in a base class, deferring some steps to subclasses.

class DataProcessor(ABC):
    def process(self):          # template method
        data = self.read()
        result = self.transform(data)
        self.write(result)

    @abstractmethod
    def read(self): ...
    @abstractmethod
    def transform(self, data): ...
    @abstractmethod
    def write(self, result): ...

46. What is a mixin?

A mixin is a class that provides methods for reuse but is not intended to stand alone or be subclassed. It adds capabilities via multiple inheritance.

class JSONMixin:
    def to_json(self):
        import json
        return json.dumps(self.__dict__)

class User(JSONMixin):
    def __init__(self, name):
        self.name = name

u = User("Alice")
print(u.to_json())   # {"name": "Alice"}

47. What is a metaclass?

A metaclass is a class whose instances are classes — it's the class of a class. Used to customise class creation (e.g., enforce interfaces, add methods at class creation time).

class SingletonMeta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class Config(metaclass=SingletonMeta):
    pass

48. What is the difference between IS-A and HAS-A relationships?

Relationship Implementation Example
IS-A Inheritance Dog IS-A Animal
HAS-A Composition/Aggregation Car HAS-A Engine

Test: can you say "X is a Y" truthfully? If yes, inheritance may be appropriate. If the relationship is "X has a Y" or "X uses a Y", prefer composition.

49. What is the difference between an object and a reference?

In Java and Python, variables hold references (pointers) to objects on the heap — not the objects themselves.

String a = "hello";
String b = a;        // b holds the same reference as a
b = "world";         // a still "hello" — reassigned b's reference, not the object

Mutation via a reference does affect the original:

a = [1, 2, 3]
b = a            # b refers to same list
b.append(4)
print(a)         # [1, 2, 3, 4]

50. What is immutability in OOP?

An immutable object cannot be changed after creation. Immutability makes objects thread-safe, safe to share, and easier to reason about.

Language Immutable examples
Java String, Integer, LocalDate
Python str, tuple, int, frozenset
JavaScript const (reference), Object.freeze()
String s = "hello";
s.toUpperCase();        // returns new String — original unchanged
System.out.println(s);  // "hello"

Common OOP mistakes

Mistake Problem Fix
God class One class does everything Split by SRP
Anemic domain model Classes have only getters/setters, no behaviour Move logic into the class
Deep inheritance hierarchies Fragile, hard to change Prefer composition
Overusing Singleton Global mutable state, hard to test Use dependency injection
Ignoring encapsulation Public fields everywhere Make fields private, expose through methods
Primitive obsession Passing raw strings/ints instead of value objects Wrap in meaningful types
Leaky abstraction Internal details bleed through the interface Design interfaces from the caller's perspective
Premature inheritance Inheriting for code reuse, not "is-a" Use composition or mixins

OOP vs other paradigms

OOP Functional Procedural
Core unit Object Function Procedure
State Mutable (encapsulated) Immutable Global/local
Code reuse Inheritance, composition Higher-order functions Functions
Best for Large systems, domain modelling Data pipelines, concurrency Scripts, small programs
Examples Java, C++, Python Haskell, Erlang, F# C, Bash

Many modern languages blend paradigms: Python, Scala, Kotlin, Rust, JavaScript.


Frequently asked questions

Q: Can a class inherit from multiple classes in Java?
A: No — Java supports single inheritance for classes. A class can implement multiple interfaces, which provides similar flexibility without the Diamond Problem.

Q: What is the difference between == and .equals() in Java?
A: == compares references (memory addresses). .equals() compares content. For objects always use .equals() unless you explicitly want reference comparison.

Q: Is Python fully object-oriented?
A: Python is multi-paradigm. Everything is an object (even int and functions), but Python does not force you to use classes — you can write procedural or functional code freely.

Q: What does virtual mean in C++?
A: A virtual function enables runtime polymorphism (dynamic dispatch). Without virtual, calling a method through a base pointer always invokes the base version, even if the object is a derived type.

Q: When should I use inheritance vs composition?
A: Use inheritance only for genuine IS-A relationships where the subclass truly is a specialisation of the parent. Prefer composition for code reuse, flexibility, and easier testing.

Q: What is the difference between an abstract class and an interface in Python?
A: Python does not have a built-in interface keyword. Abstract base classes (ABCs via abc.ABC) serve a similar role. Unlike Java, Python ABCs can have concrete methods and state, so the distinction is less sharp. The convention is to use ABCs when you want to enforce a contract with optional shared implementation.

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools