RSRobince Studio

OOP interview revision notes

Interview-focused OOP revision. Written for developers preparing for an interview who want to refresh their OOP fast. Free, no sign-up.

19 topics in these notes

  1. What is OOP?
  2. Class & Object
  3. Abstraction
  4. Encapsulation
  5. Inheritance
  6. Polymorphism
  7. Constructors & Overloading
  8. Method Overriding
  9. Abstract classes
  10. Interfaces
  11. Association, Aggregation, Composition
  12. SOLID principles (overview)
  13. Single Responsibility Principle (S)
  14. Open / Closed Principle (O)
  15. Liskov Substitution Principle (L)
  16. Interface Segregation Principle (I)
  17. Dependency Inversion Principle (D)
  18. Common design patterns
  19. OOP in JavaScript (prototype vs class)

What is OOP?

Simple real-life example (Understand first — very important for understanding)

  • Think about a car.
  • Car has data: color, speed, fuel.
  • Car has behavior: start(), stop(), accelerate().

Real-world things have state + behavior. OOP models software in the same way. Object-Oriented Programming organizes code around objects.

Technical definition

  • Object-Oriented Programming organizes code around objects.
  • Objects contain data (state) and methods (behavior).
  • Based on four pillars: Abstraction, Encapsulation, Inheritance, Polymorphism.

Simple practical example

  • Invoice object contains customer + items.
  • Invoice calculates total using its own method.

Code example

class Invoice {
  Customer customer;
  List<LineItem> items;

  Money total() {
    // calculate total
  }
}

Why it matters

  • Makes code modular.
  • Easier to maintain.
  • Improves scalability.

Interview tip

  • Explain OOP as modeling real-world entities with state + behavior.
  • Mention all four pillars clearly.

Class & Object

Simple real-life example (Understand first — very important for understanding)

  • Blueprint of a house = Class.
  • Actual built house = Object.

Class defines structure. Object is the real instance you create from it.

Technical definition

  • Class is a template defining fields and methods.
  • Object is an instance created from a class.
  • Objects hold actual data.

Simple practical example

  • User class defines name and email.
  • Each created User is a separate object.

Code example

class User {
  String name;
  String email;
}

User u = new User();

Why it matters

  • Helps structure code properly.
  • Makes system design easier.

Interview tip

  • Class = blueprint.
  • Object = instance.

Abstraction

Simple real-life example (Understand first — very important for understanding)

Imagine you are using a TV remote control.

  • You press the Power button → TV turns ON.
  • You press Volume + → Sound increases.
  • You don't know:
    • How signals travel
    • How circuits work
    • How speakers produce sound

You only know what it does, not how it works internally.

Showing only necessary features and hiding internal complexity = Abstraction.

Technical definition

  • Show only what an object does.
  • Hide how it does it.
  • Separate interface from implementation.
  • Caller depends only on abstract contract.
  • Achieved using interfaces and abstract classes.

Simple practical example

  • In a payment app, you click "Pay ₹100".
  • You don't know which bank server is called.
  • You don't know how encryption works.
  • You only care that payment succeeds.

Code example

interface PaymentGateway {
  void charge(double amount);
}

class StripeGateway implements PaymentGateway {
  public void charge(double amount) {
    // Stripe logic
  }
}

class PaypalGateway implements PaymentGateway {
  public void charge(double amount) {
    // PayPal logic
  }
}

// Usage
PaymentGateway gateway = new StripeGateway();
gateway.charge(100);

Why it matters

  • Reduces coupling.
  • Makes code flexible.
  • Easy to replace implementation.
  • Improves maintainability.
  • Improves testability.

Interview tip

  • Abstraction = exposing behavior and hiding implementation.
  • Example: Remote = interface, TV internals = implementation.

Encapsulation

Simple real-life example (Understand first — very important for understanding)

  • Think of a pill (medicine) inside a capsule.
  • You swallow the capsule; you don't see or touch the medicine inside.
  • Only the capsule's outer layer is exposed.

Hiding inner details and exposing only what's needed = Encapsulation.

Technical definition

  • Bundle data and methods that operate on that data inside one class.
  • Hide internal state with access modifiers (private / protected).
  • Expose only necessary operations (getters, setters, or higher-level methods).

Simple practical example

  • Bank account: balance is hidden (private).
  • You can only deposit or withdraw through public methods.

Code example

class BankAccount {
  private double balance;

  public void deposit(double amount) { if (amount > 0) balance += amount; }
  public void withdraw(double amount) { /* check funds */ }
  public double getBalance() { return balance; }
}

Why it matters

  • Reduces coupling.
  • Protects invariants.
  • Changing internals does not break users of the class.

Interview tip

  • Encapsulation = wrapping data + methods and restricting direct access using private and public methods.

Inheritance

Simple real-life example (Understand first — very important for understanding)

  • Child inherits traits from parents: eye color, height.
  • Child can also have own traits: favorite subject.

Reusing and extending what already exists = Inheritance. Child class (subclass) derives from parent class (superclass).

Technical definition

  • Child class (subclass) derives from parent class (superclass).
  • Represents "is-a" relationship: Dog is-an Animal.
  • Reuses and can extend parent's behavior.

Simple practical example

  • SavingsAccount is-a BankAccount.
  • SavingsAccount gets deposit/withdraw and adds interest logic.

Code example

class Animal { void makeSound() { ... } }
class Dog extends Animal {
  void makeSound() { System.out.println("Bark"); }
}

Why it matters

  • Code reuse.
  • Know when to use it; prefer composition over inheritance when appropriate.

Interview tip

  • Inheritance = is-a relationship. Prefer composition over inheritance for flexibility.

Polymorphism

Simple real-life example (Understand first — very important for understanding)

  • Same button "Save" can save as PDF, Word, or image.
  • One action, different behavior based on context.

Same interface, different implementations = Polymorphism. "Many forms" — same interface, different implementations.

Technical definition

  • "Many forms" — same interface, different implementations.
  • Compile-time: overloading (same name, different parameters).
  • Run-time: overriding (subclass replaces parent method).

Simple practical example

  • List interface: ArrayList and LinkedList both implement it.
  • Code that uses List works with either implementation.

Code example

Animal a = new Dog();   // upcasting
a.makeSound();          // calls Dog.makeSound() at runtime

Why it matters

  • Central to flexible design.
  • Strategy, State and other patterns use polymorphism.

Interview tip

  • Overriding vs overloading. Dynamic dispatch: method chosen at runtime by actual object type.

Constructors & Overloading

Simple real-life example (Understand first — very important for understanding)

  • When a new car is built, the factory sets initial state: model, color.
  • You can order "default" or "with options".

Initializing an object at creation = Constructor. Different ways to create = Overloading. Constructor: special method called when object is created; initializes state.

Technical definition

  • Constructor: special method called when object is created; initializes state.
  • Overloading: same method name, different parameter types or count; resolved at compile time.

Simple practical example

  • Point() creates (0, 0).
  • Point(2, 3) creates point at 2, 3.

Code example

class Point {
  int x, y;
  Point() { this(0, 0); }
  Point(int x, int y) { this.x = x; this.y = y; }
}

Why it matters

  • Good initialization avoids half-constructed objects.
  • Overloading is compile-time polymorphism.

Interview tip

  • Overloading = same name, different parameters. Constructors can be overloaded.

Method Overriding

Simple real-life example (Understand first — very important for understanding)

  • Parent says "greet": parent waves.
  • Child overrides "greet": child says "Hi!" instead.

Subclass provides its own version of a parent's method = Overriding. Subclass provides own implementation of a method defined in parent (same signature).

Technical definition

  • Subclass provides own implementation of a method defined in parent (same signature).
  • Enables run-time polymorphism: base reference calls overridden method in actual subclass.
  • Use @Override (or equivalent) to avoid signature mistakes.

Simple practical example

  • Shape has draw(). Circle overrides draw() to draw a circle.

Code example

class Shape { void draw() { ... } }
class Circle extends Shape {
  @Override void draw() { /* draw a circle */ }
}

Why it matters

  • How you specialize behavior.
  • Many framework callbacks rely on overriding base methods.

Interview tip

  • Overloading vs overriding: overloading = same name different params; overriding = same signature, subclass implementation.

Abstract classes

Simple real-life example (Understand first — very important for understanding)

  • You never buy "a vehicle" from a showroom — you buy a Car or Bike.
  • "Vehicle" is a category; concrete things are Car, Bike.

Abstract class = incomplete template; you extend it to create concrete classes. Cannot be instantiated directly; used as base for other classes.

Technical definition

  • Cannot be instantiated directly; used as base for other classes.
  • May contain abstract methods (no body) and concrete methods.
  • Good when subclasses share some implementation and need to define specific behavior.

Simple practical example

  • Vehicle has move() abstract and stop() concrete.
  • Car and Bike extend Vehicle and implement move().

Code example

abstract class Vehicle {
  abstract void move();
  void stop() { /* common stop code */ }
}

Why it matters

  • Interface vs abstract class: use abstract class when implementations are related and share code.

Interview tip

  • Abstract class = shared code + enforced methods. Interface = contract only (or with default methods).

Interfaces

Simple real-life example (Understand first — very important for understanding)

  • Power socket is a contract: any device that fits can get power.
  • You don't care if it's a phone or laptop — both fulfill the "plug and use" contract.

Interface = contract (what) without implementation (how). Defines method signatures without implementation (or with default methods in Java 8+).

Technical definition

  • Defines method signatures without implementation (or with default methods in Java 8+).
  • Classes can implement multiple interfaces.
  • Great for dependency inversion and mocking in tests.

Simple practical example

  • Repository interface: findById().
  • SqlUserRepository and InMemoryUserRepository both implement it.

Code example

interface Repository {
  User findById(String id);
}

class SqlUserRepository implements Repository { ... }
class InMemoryUserRepository implements Repository { ... }

Why it matters

  • Central to clean architecture and testability.
  • Depend on interfaces, not concrete classes.

Interview tip

  • Interfaces = "what" without "how". Used for injection and mocking.

Association, Aggregation, Composition

Simple real-life example (Understand first — very important for understanding)

  • Association: Teacher knows Students (uses/knows).
  • Aggregation: Team has Players; players can leave and join another team (weak has-a).
  • Composition: House has Rooms; rooms don't exist without the house (strong has-a).

Strength of "has-a" and lifecycle ownership defines the relationship type. Association: general relationship between two classes.

Technical definition

  • Association: general relationship between two classes.
  • Aggregation: whole–part; part can exist independently.
  • Composition: whole owns part; part's lifecycle tied to whole.

Simple practical example

  • Order contains OrderLines; when Order is deleted, lines go too = composition.

Code example

class Order {           // composition
  private List<OrderLine> lines = new ArrayList<>();
}

Why it matters

  • Design and UML questions often ask you to classify relationships.
  • Good modeling uses composition more than inheritance.

Interview tip

  • Association = uses; aggregation = has-a but independent; composition = has-a and owned lifecycle.

SOLID principles (overview)

Simple real-life example (Understand first — very important for understanding)

  • Single tool does one job well (knife cuts, spoon scoops).
  • You extend with new tools instead of modifying the knife to also scoop.

SOLID = five principles for better OO design and maintainability. S ingle Responsibility — one reason to change.

Technical definition

  • Single Responsibility — one reason to change.
  • Open / Closed — open for extension, closed for modification.
  • Liskov Substitution — subtype substitutable for base type.
  • Interface Segregation — many small interfaces better than one fat interface.
  • Dependency Inversion — depend on abstractions, not concretions.

Simple practical example

  • UserService depends on Repository interface, not SqlRepository — so you can inject InMemoryRepository for tests.

Code example

class UserService {
  private final Repository repo;
  UserService(Repository repo) { this.repo = repo; }
}

Why it matters

  • SOLID comes up in mid/senior interviews.
  • Vocabulary for talking about good OO design.

Interview tip

  • List all five and give a 1-2 line explanation + tiny example for S and D.

Single Responsibility Principle (S)

Simple real-life example (Understand first — very important for understanding)

  • Chef cooks; waiter serves; cashier bills.
  • One person, one main job.

One reason to change per class = Single Responsibility. A class should have one reason to change — one primary responsibility.

Technical definition

  • A class should have one reason to change — one primary responsibility.
  • Split unrelated responsibilities: e.g. InvoiceCalculator, InvoiceRepository, InvoicePrinter.

Simple practical example

  • Instead of one God class doing business + DB + printing, split into separate classes.

Code example

class InvoiceService { /* business rules */ }
class InvoiceRepository { /* DB persistence */ }

Why it matters

  • Easiest and most impactful principle.
  • Many design smells are SRP violations.

Interview tip

  • "One reason to change" — show you understand splitting responsibilities.

Open / Closed Principle (O)

Simple real-life example (Understand first — very important for understanding)

  • USB port: you add new devices without changing the port.
  • Extend by plugging in, not by modifying the laptop.

Open for extension, closed for modification = add new code without editing existing. Classes open for extension, closed for modification.

Technical definition

  • Classes open for extension, closed for modification.
  • Achieved via polymorphism, interfaces, composition — not big if/else on type.
  • Add new strategies without editing old ones.

Simple practical example

  • DiscountPolicy interface; NoDiscount, SeasonalDiscount implement it. New discount = new class.

Code example

interface DiscountPolicy { Money apply(Money total); }
class NoDiscount implements DiscountPolicy { ... }
class SeasonalDiscount implements DiscountPolicy { ... }

Why it matters

  • Reduces regression risk: add new code instead of editing tested code.

Interview tip

  • Replace "switch on type" with polymorphic classes implementing a common interface.

Liskov Substitution Principle (L)

Simple real-life example (Understand first — very important for understanding)

  • Where you use "Bird", you can put "Sparrow" — it still flies, sings.
  • If you put "Penguin" (can't fly), code that expects "fly()" breaks — that's an LSP violation.

Subtype must be substitutable for base type without breaking correctness. Objects of superclass replaceable by objects of subclass without breaking correctness.

Technical definition

  • Objects of superclass replaceable by objects of subclass without breaking correctness.
  • Subclasses must not weaken postconditions or strengthen preconditions.
  • Classic violation: Square extends Rectangle but setWidth/setHeight break expectations.

Simple practical example

  • Code that uses setWidth and setHeight independently breaks if Square sets both together.

Code example

// If code relies on setWidth, setHeight independently,
// Square that sets both may violate assumptions.

Why it matters

  • Designs safe inheritance hierarchies.
  • Violations cause surprising behavior and subtle bugs.

Interview tip

  • Subtypes must be substitutable for base types. Use Rectangle/Square example.

Interface Segregation Principle (I)

Simple real-life example (Understand first — very important for understanding)

  • You need to print; you don't want to implement scan, fax, copy.
  • Small, focused "contracts" are better than one huge contract.

Many small interfaces better than one fat interface = Interface Segregation. Clients should not depend on methods they do not use.

Technical definition

  • Clients should not depend on methods they do not use.
  • Split fat interfaces into focused ones: e.g. Printer, Scanner, Closable.

Simple practical example

  • Printer interface has print(); Scanner interface has scan(). Not one Device with both.

Code example

interface Printer { void print(Document d); }
interface Scanner { void scan(Document d); }

Why it matters

  • Reduces coupling; changes in one responsibility don't break unrelated clients.

Interview tip

  • Give example of a bloated interface and how you'd split it into smaller ones.

Dependency Inversion Principle (D)

Simple real-life example (Understand first — very important for understanding)

  • You depend on "power outlet" (abstraction), not "this specific generator" (detail).
  • Any source that fits the outlet works.

Depend on abstractions, not concrete details = Dependency Inversion. High-level modules should not depend on low-level modules; both depend on abstractions.

Technical definition

  • High-level modules should not depend on low-level modules; both depend on abstractions.
  • Abstractions should not depend on details; details depend on abstractions.
  • Use constructor injection, DI containers, interfaces for DB/messaging.

Simple practical example

  • NotificationService depends on MailSender interface; inject real or mock in tests.

Code example

class NotificationService {
  private final MailSender mailSender;  // interface
  NotificationService(MailSender mailSender) { this.mailSender = mailSender; }
}

Why it matters

  • Core of clean architecture and testability.
  • Swap implementations (real DB vs in-memory) easily.

Interview tip

  • DI makes unit testing easy (inject mocks) and decouples business logic from infrastructure.

Common design patterns

Simple real-life example (Understand first — very important for understanding)

  • Singleton: one company CEO — everyone goes to the same person.
  • Factory: car factory produces different models from one assembly line.
  • Strategy: same "pay" button can use card, UPI, or cash.

Reusable solutions to common design problems = Design patterns. Singleton : one instance globally; beware testability.

Technical definition

  • Singleton: one instance globally; beware testability.
  • Factory: encapsulate object creation (e.g. ShapeFactory.create('circle')).
  • Strategy: choose algorithm at runtime via interface.
  • Observer: one-to-many notifications (event listeners, UI bindings).

Simple practical example

  • DiscountStrategy interface: NoDiscount, CouponDiscount implement it.

Code example

interface DiscountStrategy { Money apply(Money total); }
class NoDiscount implements DiscountStrategy { ... }
class CouponDiscount implements DiscountStrategy { ... }

Why it matters

  • Patterns are named combinations of OO principles.
  • Interviews ask you to recognize or propose one for a scenario.

Interview tip

  • Know 3–4 patterns with use-cases; no need to memorize all 23 GoF patterns.

OOP in JavaScript (prototype vs class)

Simple real-life example (Understand first — very important for understanding)

  • Think of a family tree: Grandparent → Parent → Child.
  • Child automatically "gets" traits from parent and grandparent, but can add its own.
  • In JS, objects inherit from other objects in a similar chain (prototype chain).

Instead of "class files" like Java, JavaScript links objects together in a chain; the class keyword is just a nicer way to work with that model.

Technical definition

  • JavaScript is prototype-based: every object has an internal [[Prototype]] that points to another object (or null).
  • When you access obj.method(), JS first checks obj; if not found, it walks up the prototype chain.
  • Calling a function with new creates a new object whose prototype is Func.prototype.
  • ES6 class, constructor, extends, super are syntax sugar over this prototype mechanism.
  • Encapsulation can be done with closures (functions that capture local variables) and with modern private fields (e.g. #balance).

Simple practical example

  • You can model a Person and a Student using prototypes or using the class keyword.
  • Both approaches share behavior (methods) instead of duplicating it on each instance.
  • Most modern code uses class, but understanding prototypes helps you debug and answer interview questions.

Code example (prototype style vs class)

// Prototype style
function Person(name) {
  this.name = name;
}
Person.prototype.greet = function() {
  console.log("Hi " + this.name);
};

function Student(name, grade) {
  Person.call(this, name);             // call "base constructor"
  this.grade = grade;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

const s1 = new Student("Alex", 10);
s1.greet(); // "Hi Alex"

// Class style (syntactic sugar over prototypes)
class PersonClass {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log("Hi " + this.name);
  }
}

class StudentClass extends PersonClass {
  constructor(name, grade) {
    super(name);          // calls PersonClass constructor
    this.grade = grade;
  }
}

const s2 = new StudentClass("Sam", 9);
s2.greet(); // "Hi Sam"

Why it matters

  • Almost all modern JS frameworks (React classes, older Angular, many libraries) use the prototype/class model under the hood.
  • Understanding prototypes explains how methods are shared, how inheritance works, and why this behaves differently in arrow vs regular functions.
  • Interviewers often ask: "Is JS class-based or prototype-based?" or "How does extends work internally?"

Interview tip

  • Answer: "JavaScript is prototype-based. The class keyword is syntax sugar over prototypes; extends sets up the prototype chain and super() calls the parent constructor."
  • Be ready to show a tiny example with class and briefly mention the prototype chain.
  • If asked to compare with Java/C#: emphasize dynamic objects, prototype chain, and that there is no separate "class file" at runtime.

More Design & Architecture notes

Data Structures · Microservices · Project Architecture · System Design · All developer notes