OOP interview questions and oops interview questions appear in almost every software interview—from campus placements to senior system design loops. Panels want more than definitions: they expect you to explain encapsulation vs abstraction, defend composition over inheritance, walk through compile-time vs runtime polymorphism, and apply SOLID to a real class diagram. Java oops interview questions are especially common in India and enterprise hiring because Java remains the default teaching language for object-oriented design.
Below are 40+ OOP interview questions grouped by topic. Each response explains the concept and ends with a strong answer you can adapt in an interview. This guide is language-aware but emphasizes Java where interviewers drill syntax (abstract, interface, access modifiers). For JVM and Java-specific depth beyond OOP, continue with Java interview questions part 1 and part 2. For C++ OOP and memory, see C and C++ interview questions. For Python's object model and duck typing, see Python developer interviews.
Interview context and how to prepare
What OOP interviews actually test
OOP interviews test whether you can model problems as objects with clear responsibilities—not whether you can recite "four pillars" without context.
| Layer | What interviewers probe |
|---|---|
| Fundamentals | Class, object, encapsulation, abstraction |
| Relationships | Inheritance, composition, association |
| Polymorphism | Overloading, overriding, dynamic dispatch |
| Java OOPs | Access modifiers, abstract, interface, super |
| Design quality | Coupling, cohesion, SOLID |
| Patterns | Strategy, Factory, Observer, when to use |
| Scenarios | Parking lot, notification system, payment module |
| Role | Emphasis |
|---|---|
| Fresher / campus | Pillars, overloading vs overriding, modifiers |
| Mid-level | Composition, SOLID, one pattern with example |
| Senior / SDET | LSP violations, DIP in frameworks, OOD whiteboard |
Typical OOP interview loop
| Round | Duration | Focus |
|---|---|---|
| Aptitude / screening | 30 min | Basics, four pillars, Java syntax |
| Technical — fundamentals | 45–60 min | Inheritance, polymorphism, abstract vs interface |
| Technical — design | 45–60 min | SOLID, patterns, composition |
| Live coding / OOD | 45–60 min | Class diagram, implement small hierarchy |
| Managerial | 30 min | Team practices, code review, refactoring stories |
Experienced loops expect you to connect pillars, SOLID, and patterns to real class design—not recite definitions alone.
Realistic 3–5 week OOP prep plan
| Week | Focus | Output |
|---|---|---|
| 1 | Four pillars + class diagrams | Explain each with one example |
| 2 | Inheritance, composition, polymorphism | Runnable Java demos |
| 3 | Abstract class vs interface, Java modifiers | Cheat sheet you can draw |
| 4 | SOLID + 3 patterns | One pattern per creational/behavioral |
| 5 | OOD scenarios + mock | Whiteboard parking lot or library |
Draw UML-style boxes on paper—interviewers reward clear entity relationships.
OOP vs procedural programming — what is the difference?
What interviewers are testing: Whether you can explain when procedural functions fit scripts and pipelines—and when object boundaries, encapsulation, and interfaces pay off as teams and domain rules grow.
| Aspect | Procedural | Object-oriented |
|---|---|---|
| Unit of design | Functions, procedures | Classes and objects |
| State | Often global or passed parameters | Encapsulated in objects |
| Reuse | Functions, modules, libraries, composition | Classes, composition, interfaces, inheritance |
| Modeling | Step-by-step algorithms | Entities with behavior |
| Scaling teams | Globals and side effects hurt | Boundaries via classes and interfaces help in large OOP codebases |
Procedural code is fine for scripts and small tools—see shell scripting interviews. Large systems can use procedural, functional, data-oriented, or hybrid design; OOP is one common choice when many developers share a long-lived codebase with changing requirements.
A strong answer is:
Procedural code organizes logic as functions with shared state; OOP bundles state and behavior in objects—I use procedural for scripts and OOP when many developers share an evolving domain model.
How does OOP differ across Java, Python, and C++?
What interviewers are testing: Whether you can contrast Java's class-and-interface model, Python's duck typing, and C++ lifetime semantics with concrete examples—not treat all three as identical OOP.
| Feature | Java | Python | C++ |
|---|---|---|---|
| Model | Class-based; single inheritance of classes, multiple interface implementation | Class + duck typing | Multiple inheritance allowed |
| Encapsulation | private, protected, public |
Naming conventions (_name) and name mangling (__name); no Java-style private enforcement |
private, protected, public |
| Abstraction | abstract class, interface |
ABC module, protocols (3.8+) | Pure virtual classes |
| Polymorphism | Overload + override | Duck typing + override | Virtual functions, templates |
| Memory/lifetime | Garbage collection | Automatic memory management / GC | Deterministic lifetime via RAII; smart pointers, with manual control available |
Java oops interview questions focus on modifiers and interfaces. Python interviews stress duck typing—see Python interviews. C++ adds multiple inheritance and vtables—see C and C++ interviews.
A strong answer is:
Java has single class inheritance plus interfaces and GC; Python relies heavily on dynamic/duck typing and conventions rather than enforced private access; C++ adds multiple inheritance and deterministic RAII-based lifetime management.
Four pillars and core concepts
What are the four pillars of OOP?
What interviewers are testing: Whether you understand the four concepts as different design tools, not four memorized definitions.
| Pillar | Meaning | Example |
|---|---|---|
| Encapsulation | Bundle data + methods; control access | private balance + deposit() |
| Abstraction | Expose what, hide how | PaymentGateway.charge() hides PCI details |
| Inheritance | Model an IS-A subtype relationship | SavingsAccount extends Account |
| Polymorphism | One interface, many behaviors | Shape.draw() for Circle vs Square |
The pillars work together: encapsulation protects state, abstraction simplifies usage, inheritance shares structure, polymorphism lets callers depend on supertypes.
A strong answer is:
I name all four and immediately ground each in code—private fields for encapsulation, an interface for abstraction, extends for inheritance, and overriding draw() for polymorphism.
What is the difference between a class and an object?
What interviewers are testing: Whether you distinguish a type definition from runtime instances and per-instance state.
| Term | Definition |
|---|---|
| Class | Blueprint—fields, methods, constructors |
| Object | Runtime instance created from a class |
| Instance | Synonym for object in many interviews |
class Dog {
String name;
void bark() { System.out.println("woof"); }
}
Dog rex = new Dog(); // rex is an object (instance) of class DogOne class → many objects (new Dog() twice yields two instances with separate state).
A strong answer is:
A class is the template; an object is a concrete instance at runtime with its own field values—one
Carclass, manyCarobjects in a fleet.
What is encapsulation?
What interviewers are testing: Whether you protect invariants and implementation boundaries, not merely make every field private.
Encapsulation binds data and methods that operate on that data into one unit (usually a class) and restricts direct access to internal state.
Benefits:
- Invariant protection — balance cannot go negative if
withdrawvalidates - Refactoring freedom — change internal representation without breaking callers
- Controlled access — callers cannot mutate implementation state directly
public class BankAccount {
private int balance;
public void deposit(int amount) {
if (amount > 0) balance += amount;
}
public int getBalance() { return balance; }
}A strong answer is:
Encapsulation keeps state private and exposes behavior through methods so invariants stay enforced—I never let callers set
balancedirectly if rules matter.
What is abstraction?
What interviewers are testing: Whether you can expose a stable useful contract while hiding implementation choices.
Abstraction hides implementation complexity and shows only essential behavior—the "what" without the "how."
| Mechanism | Role |
|---|---|
| Abstract class | Partial implementation + shared code |
| Interface | Type contract—modern Java interfaces may contain default, static, and private helper methods |
| Public API | Service method names hide database/HTTP details |
Driving a car: you use accelerate()—not spark-plug timing. That is abstraction at the human level; in code, List lets callers program to list operations without depending on whether the concrete implementation is ArrayList, LinkedList, or another implementation.
A strong answer is:
Abstraction is the simplified surface—an interface or abstract API—so callers depend on capabilities like charge() without knowing Stripe vs PayPal wiring.
Encapsulation vs abstraction — what is the difference?
What interviewers are testing: Whether you can distinguish protecting internal state from simplifying what callers need to know.
| Encapsulation | Abstraction | |
|---|---|---|
| Focus | Protecting data | Hiding complexity |
| Level | Implementation (how data is guarded) | Design (what you expose) |
| Mechanism | private fields, getters |
Interfaces, abstract classes |
| Question answered | "Who can touch this state?" | "What can this thing do?" |
You can encapsulate without strong abstraction (public getters for everything). You can abstract without strict encapsulation (leaky interface returning internals).
A strong answer is:
Encapsulation guards state with access control; abstraction hides how work is done behind a simpler contract—I need both, but they answer different design questions.
What is data hiding and how does it relate to encapsulation?
What interviewers are testing: Whether you understand that visibility control is one mechanism used by encapsulation, not a synonym for it.
Data hiding restricts unnecessary visibility of implementation details, commonly with private or package-scoped access and, where inheritance genuinely requires it, protected.
| Concept | Scope |
|---|---|
| Encapsulation | Broader—bundling data + behavior |
| Data hiding | Narrower—visibility of fields |
Encapsulation can exist with public fields (weak hiding). Production code should hide data and expose behavior.
A strong answer is:
Data hiding is the access-modifier part of encapsulation—I use private fields so internal representation can change without breaking every caller.
What is inheritance?
What interviewers are testing: Whether you use inheritance for true substitutable subtype relationships, rather than code reuse alone.
Inheritance creates a subtype relationship in which a child class derives behavior and state from a parent and can be used where that parent type is expected—an IS-A relationship.
class Animal {
void eat() { System.out.println("eating"); }
}
class Dog extends Animal {
void bark() { System.out.println("woof"); }
}Shared implementation is a benefit, but inheritance should model a valid IS-A/substitution relationship rather than being chosen only to avoid duplicate code. Risks: tight coupling, fragile base class, deep trees—often replaced by composition for HAS-A.
A strong answer is:
Inheritance models IS-A reuse and enables overriding; I avoid deep trees and prefer composition when behavior is shared but not a true subtype relationship.
What is polymorphism?
What interviewers are testing: Whether you can program to a supertype/interface and let implementations vary without changing callers.
Polymorphism ("many forms") lets one interface or superclass reference invoke different implementations depending on the actual object type.
Interview terminology often calls method overloading "compile-time/static polymorphism," although subtype polymorphism specifically refers to substitutable implementations and dynamic dispatch.
Two forms in Java:
| Type | Mechanism | Binding |
|---|---|---|
| Compile-time | Method overloading | Static |
| Runtime | Method overriding | Dynamic |
interface Notifier {
String send(String message);
}
class EmailNotifier implements Notifier {
public String send(String message) { return "email:" + message; }
}
class SmsNotifier implements Notifier {
public String send(String message) { return "sms:" + message; }
}
public class PolymorphismDemo {
static String notifyUser(Notifier n, String msg) {
return n.send(msg);
}
public static void main(String[] args) {
System.out.println(notifyUser(new EmailNotifier(), "hello"));
System.out.println(notifyUser(new SmsNotifier(), "hello"));
}
}The same notifyUser method accepts any Notifier; runtime dispatch picks email: vs sms: output.
A strong answer is:
Polymorphism lets callers depend on a common supertype while different implementations provide behavior at runtime. In Java interviews, method overloading is also commonly called compile-time polymorphism, while overriding gives true runtime dispatch.
Inheritance, composition, and relationships
What are the types of inheritance?
What interviewers are testing: Whether you know Java's class-inheritance limitation and how interfaces provide multiple type inheritance.
| Type | Structure | Example |
|---|---|---|
| Single | One parent | Dog extends Animal |
| Multilevel | Chain | GoldenRetriever extends Dog extends Animal |
| Hierarchical | Many children, one parent | Cat, Dog extend Animal |
| Multiple | Several parents | C++ yes; Java classes no |
| Hybrid | Combination | Mix of hierarchical + multiple (via interfaces in Java) |
Java classes: single inheritance of classes, multiple interface implementation.
A strong answer is:
Java gives single class inheritance and multiple interfaces—I describe multilevel and hierarchical with Animal examples and mention C++ for true multiple inheritance contrast.
Composition vs inheritance — when do you choose each?
What interviewers are testing: Whether you can recognize when HAS-A delegation creates safer flexibility than IS-A coupling.
| Inheritance (IS-A) | Composition (HAS-A) | |
|---|---|---|
| Relationship | Subtype | Contains / uses |
| Coupling | Tight to parent | Looser—swap parts |
| Flexibility | Fixed at compile hierarchy | Inject strategies at runtime |
| Risk | Fragile base class | Slightly more boilerplate |
interface Engine {
String start();
}
final class PetrolEngine implements Engine {
public String start() { return "vroom"; }
}
final class Car {
private final Engine engine;
Car(Engine engine) {
this.engine = engine;
}
String drive() {
return engine.start();
}
}
public class CompositionDemo {
public static void main(String[] args) {
System.out.println(new Car(new PetrolEngine()).drive());
}
}Favor composition when behavior varies or lifetime is HAS-A. Use inheritance for genuine taxonomic subtyping and shared interface contracts.
A strong answer is:
I default to composition for reusable behavior—Car has Engine—and reserve inheritance for true IS-A subtypes where Liskov substitution holds.
Aggregation vs composition vs association?
What interviewers are testing: Whether you understand the relationships as different ownership/lifetime semantics in the domain model.
| Relationship | Ownership | Lifetime |
|---|---|---|
| Association | Uses | Independent |
| Aggregation | Weak HAS-A | Part can outlive whole |
| Composition | Strong HAS-A | Part dies with whole |
Example: Doctor associated with Patient; Team aggregates Player objects that can exist independently; House composes Room objects as parts of that modeled house.
Java does not mechanically enforce UML "part dies with whole" lifecycle rules—composition here is a domain-model ownership concept.
A strong answer is:
Composition is strict ownership in the domain model—house and its rooms; aggregation is looser—team and players who can exist independently; association is mere usage—doctor and patient.
IS-A vs HAS-A — explain with examples.
What interviewers are testing: Whether you can spot an inheritance relationship that fails behavioral substitutability.
| Relation | Keyword in design | Example |
|---|---|---|
| Subtype relation | extends / implements |
ElectricCar subtype of Car |
| HAS-A | Field reference | Car HAS-A Engine |
Interview trap: modeling Stack extends ArrayList IS-A wrong for behavior—Stack HAS-A list (composition) avoids LSP violations.
A strong answer is:
IS-A for subtype polymorphism; HAS-A when one object contains or uses another—I rejected Stack extends ArrayList because a stack is not an array list behaviorally.
What is the diamond problem in multiple inheritance?
What interviewers are testing: Whether you understand ambiguity caused by multiple inherited implementations and Java's resolution rules.
When class D inherits B and C, and both B and C inherit A and override the same method, D faces ambiguous which override to use:
A
/ \
B C
\ /
DJava does not support multiple inheritance of classes, so this form of multiple-base-class ambiguity cannot occur through class extension. Interfaces can still inherit conflicting default methods; Java requires the implementing class to resolve such conflicts explicitly. C++ allows multiple class inheritance and addresses ambiguity with mechanisms such as virtual inheritance.
A strong answer is:
Java avoids class-extension diamond ambiguity by allowing only one superclass—I use interfaces and override explicitly when default methods conflict.
How does Java achieve multiple inheritance without extending two classes?
What interviewers are testing: Whether you know Java supports multiple interfaces/types but only one superclass.
A class may:
class PaymentService implements Auditable, Retryable, MetricsAware { }Interfaces define contracts; a class implements many. Since Java 8, default methods on interfaces share implementation—but conflicting defaults require an override in the class.
A strong answer is:
Java gives multiple inheritance of type through interfaces, not multiple class extension—default methods add shared code with explicit conflict rules.
Method overloading vs method overriding?
What interviewers are testing: Whether you understand compile-time overload selection vs runtime override dispatch.
| Overloading | Overriding | |
|---|---|---|
| Same name | Yes, different parameters | Same name and parameter types; compatible/covariant return type |
| Class | Same class (or inherited) | Parent-child |
| Polymorphism | Compile-time (static) | Runtime (dynamic) |
| Return type | Can differ if params differ | Covariant returns allowed |
| Access | Any | Cannot reduce visibility |
class Calc {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; } // overload
}
class Parent { String greet() { return "hi"; } }
class Child extends Parent {
@Override String greet() { return "hello"; } // override
}A strong answer is:
Overloading is same method name, different parameters, resolved at compile time; overriding is subclass replacing parent behavior, resolved at runtime via dynamic dispatch.
Polymorphism, abstraction, and Java types
What is compile-time (static) polymorphism?
What interviewers are testing: Whether you understand how Java chooses an overloaded signature from compile-time types.
Achieved through method overloading. C++ supports user-defined operator overloading; Java does not allow user-defined operator overloads (though + has predefined behavior for numbers and strings).
The compiler resolves the overloaded method using the compile-time types of the receiver and arguments, plus Java's overload-resolution rules:
class Printer {
void print(int x) { System.out.println("int:" + x); }
void print(String s) { System.out.println("str:" + s); }
}
public class StaticPoly {
public static void main(String[] args) {
Printer p = new Printer();
p.print(42);
p.print("hi");
}
}Running prints int:42 then str:hi—the compiler bound each call statically.
A strong answer is:
Compile-time or static polymorphism is the common interview term for method overloading: the compiler selects the applicable method from compile-time argument types. Java does not support user-defined operator overloading like C++.
What is runtime (dynamic) polymorphism?
What interviewers are testing: Whether you understand dynamic dispatch based on the runtime object's overridden method.
Achieved through method overriding: reference type is superclass/interface; actual object type decides which method runs.
For overridable instance methods, Java uses runtime dynamic dispatch based on the actual object type. JVM implementations optimize this using techniques such as method tables, inline caches, and JIT devirtualization. final, static, and private methods do not participate in runtime override dispatch the same way.
A strong answer is:
Runtime polymorphism is overriding—a variable typed as Animal holding a Dog calls Dog's speak() at runtime because dispatch uses the object's actual class.
What are upcasting and downcasting?
What interviewers are testing: Whether you can use supertypes normally and recognize that frequent downcasting often signals weak abstraction.
| Cast | Direction | Safety |
|---|---|---|
| Upcasting | Child → parent | Implicit, always safe |
| Downcasting | Parent → child | Explicit, can fail |
Animal a = new Dog(); // upcast (implicit)
Dog d = (Dog) a; // downcast — ClassCastException if wrong
if (a instanceof Dog dog) { // Java 16+ pattern matching
dog.bark();
}Prefer polymorphism so downcasting is unnecessary. When the runtime type is genuinely uncertain, use instanceof / pattern matching before accessing subtype-specific behavior.
A strong answer is:
Upcast to general types for polymorphism; downcast only when needed and after instanceof—or better, redesign with polymorphism so the cast disappears.
What is an abstract class?
What interviewers are testing: Whether you know when a shared base needs state/implementation plus extension points.
An abstract class cannot be instantiated; it may contain abstract methods (no body) and concrete methods.
abstract class Shape {
abstract double area();
void label() { System.out.println("shape"); }
}Use when subtypes share common state or implementation but need specialized behavior.
A strong answer is:
Abstract classes are partial blueprints—I share code and fields in Shape while forcing Circle to implement area().
What is an interface?
What interviewers are testing: Whether you understand interfaces as contracts/capabilities decoupled from a concrete implementation.
An interface defines a type contract. Its abstract methods must be implemented by a concrete class unless inherited implementation satisfies them; modern interfaces may also provide default, static, and private helper methods. Fields declared in an interface are implicitly public static final constants.
interface Persistable {
void save();
void delete();
default void archive() { save(); }
}
class User implements Persistable {
public void save() { /* ... */ }
public void delete() { /* ... */ }
}Implementors do not need to implement default methods unless they override them. A class may implement multiple interfaces.
A strong answer is:
Interfaces define what a type can do without dictating inheritance tree—I implement several on one service class for cross-cutting contracts.
Abstract class vs interface — when do you use each?
What interviewers are testing: Whether you choose between shared base implementation and multiple capability contracts.
| Factor | Abstract class | Interface |
|---|---|---|
| Instantiation | No | No |
| Multiple inherit | One class only | Many interfaces |
| State | Can have instance fields | Fields are public static final only |
| Constructors | Yes | No |
| Evolution | New concrete methods are generally compatible; new abstract methods require subclass changes | New abstract methods break implementers; default methods can evolve contracts compatibly |
| Use when | Shared code + IS-A base | Capability contract |
Java 8+ blurs the line with default methods—still prefer interface for roles, abstract class for shared base implementation.
A strong answer is:
Interface for capabilities (Comparable, Runnable); abstract class when subclasses share fields and helper methods—I don't use abstract class just to block instantiation; use private constructor instead.
Java OOPs specifics
Explain Java access modifiers.
What interviewers are testing: Whether you understand Java visibility rules—including protected access across packages—not just a four-column cheat sheet.
| Modifier | Class | Package | Subclass access | World |
|---|---|---|---|---|
private |
Yes | No | No | No |
| (default) | Yes | Yes | No | No |
protected |
Yes | Yes | Yes | No |
public |
Yes | Yes | Yes | Yes |
This table is a simplification; cross-package protected access has additional rules.
Interview tip: Across packages, protected access is available to subclasses through the inherited/subclass context; it is not equivalent to general package-wide access to arbitrary superclass instances. Prefer private + public methods when possible.
A strong answer is:
I default to private fields, public behavior methods, and protected only when subclasses genuinely need hooks—package-private for internal module APIs.
What does final mean for class, method, and variable?
What interviewers are testing: Whether you understand what final prevents—and what it doesn't make immutable.
| Use | Effect |
|---|---|
final class |
Cannot be extended |
final method |
Cannot be overridden |
final variable |
May be assigned once; a final reference cannot point to another object, but the referenced object may still be mutable |
String being final prevents subclasses from changing its observable behavior, which helps preserve the guarantees callers rely on. Use final on method parameters and local variables when values should not be reassigned (readability).
A strong answer is:
finalprevents reassignment, not mutation of the referenced object. It helps build immutable types when combined with immutable state.
Static vs instance members in OOP?
What interviewers are testing: Whether you distinguish object-specific behavior from class-level state/utility and understand global-state trade-offs.
| Instance | Static | |
|---|---|---|
| Belongs to | Each object | Class |
| Access | Needs object (or this) |
Class name |
| Override | Yes (polymorphism) | No—hiding only |
| Use | Per-object state | Constants, factories, counters |
Static methods cannot access instance fields directly. Overuse of static hurts testability and OOP boundaries—see also Java part 1 static questions.
A strong answer is:
Instance members carry per-object state; static belongs to the class—I avoid static mutable state because it breaks encapsulation and makes tests order-dependent.
What constructor rules and patterns should you know in Java?
What interviewers are testing: Whether you know constructor generation/chaining and superclass initialization, not a memorized list of constructor types.
| Concept | Meaning |
|---|---|
| Compiler-provided default constructor | Generated only when the class declares no constructor |
| Explicit no-arg constructor | Developer-written zero-parameter constructor |
| Parameterized constructor | Accepts initialization values |
| Copy-style constructor | User-defined convention; Java has no built-in copy constructor feature |
| Constructor chaining | One constructor invokes another with this(...) or a superclass constructor with super(...) |
If any constructor is defined, the compiler does not auto-generate a default. If a superclass has no accessible no-argument constructor, the subclass constructor must ultimately invoke an accessible superclass constructor with the required arguments.
A strong answer is:
I use parameterized constructors for required fields and add an explicit no-arg constructor only when frameworks need it—remembering Java removes the compiler default once I define any constructor, and that subclass constructors must reach a valid superclass constructor.
What are this and super in Java?
What interviewers are testing: Whether you understand current-instance access, superclass access, and constructor chaining rules—including modern flexible constructor bodies.
| Keyword | Refers to | Common use |
|---|---|---|
this |
Current object | Field disambiguation, this() chaining |
super |
Parent class | super() constructor, super.method() |
class Employee extends Person {
Employee(String name, int id) {
super(name);
this.id = id;
}
}this refers to the current object; super accesses superclass members or invokes a superclass constructor. Traditionally Java required explicit this(...)/super(...) as the first statement, but Java 25's flexible constructor bodies allow safe statements before that invocation as long as they do not improperly use the object before superclass construction.
A strong answer is:
thisrefers to the current instance andsuperto the superclass. I use them for field disambiguation, method access, and constructor chaining; in modern Java, safe validation or computation may occur before an explicitsuper(...)orthis(...)call.
What are default methods on interfaces (Java 8+)?
What interviewers are testing: Whether you understand how default methods let interfaces evolve without breaking every implementor.
interface Logger {
void log(String msg);
default void logInfo(String msg) { log("INFO: " + msg); }
}Allows evolving interfaces without breaking every implementor—implementors inherit default unless they override.
Conflict rule: if two interfaces provide the same default, the class must override and choose.
A strong answer is:
Default methods let me add behavior to interfaces without forcing every implementor to update—if two defaults clash, I override explicitly in the class.
Coupling, cohesion, and SOLID
What are coupling and cohesion?
What interviewers are testing: Whether you can recognize boundaries that make change and testing local instead of cascading.
| Metric | Good | Bad |
|---|---|---|
| Cohesion | Class does one focused job | God class does everything |
| Coupling | Classes depend on abstractions | Classes reach into each other's internals |
High cohesion + low coupling = easier tests and refactors. OOP tools: interfaces, composition, package-private boundaries.
A strong answer is:
I want high cohesion inside a class and loose coupling between classes—depending on PaymentGateway interface, not StripeClient concrete type.
What are the SOLID principles?
What interviewers are testing: Whether you can use SOLID as design heuristics on real code, rather than expand five acronyms.
| Letter | Principle | One line |
|---|---|---|
| S | Single Responsibility | One reason to change |
| O | Open/Closed | Open for extension, closed for modification |
| L | Liskov Substitution | Subtypes must work wherever parent worked |
| I | Interface Segregation | Small interfaces |
| D | Dependency Inversion | Depend on abstractions |
SOLID guides maintainable OOP—common in mid/senior loops and Spring Boot design discussions.
A strong answer is:
SOLID is a set of design heuristics: keep responsibilities focused, extend behavior without repeatedly modifying stable code, preserve subtype contracts, keep interfaces narrow, and make high-level logic depend on abstractions. I use them to reduce change impact, not as rigid rules.
Explain Single Responsibility Principle (SRP).
What interviewers are testing: Whether you can identify different reasons for change hidden inside one class.
A class should have only one reason to change—one axis of responsibility.
Bad: Invoice generates PDF, sends email, and calculates tax.
Better: Invoice, PdfRenderer, Mailer, TaxCalculator collaborate.
SRP improves testability—mock mailer without touching tax math.
A strong answer is:
SRP means one job per class—if email templates and tax rules change for different reasons, they belong in different classes, not one InvoiceGod.
Explain Open/Closed Principle (OCP).
What interviewers are testing: Whether changing requirements can be handled through extension instead of repeatedly editing stable branching logic.
Software entities should be open for extension, closed for modification—add behavior without editing stable code.
Pattern: Strategy — new DiscountStrategy class instead of editing checkout() switch:
interface DiscountStrategy { int apply(int total); }
class TenPercent implements DiscountStrategy {
public int apply(int total) { return total * 90 / 100; }
}A strong answer is:
OCP means I extend with new strategy or handler classes instead of patching a growing if-else in the core checkout method every time marketing adds a promo.
Explain Liskov Substitution Principle (LSP).
What interviewers are testing: Whether a subtype preserves the behavioral contract expected by callers.
A subtype violates LSP if code written for the base type behaves incorrectly or unexpectedly when given the subtype. At a more formal level, that can mean strengthened preconditions, weakened postconditions, or other broken behavioral expectations.
Classic illustration: Square extends Rectangle—setting width should not break square invariants if callers expect independent width and height semantics.
// Anti-pattern: Square changes independent width/height semantics
class Square extends Rectangle {
void setWidth(int w) { super.setWidth(w); super.setHeight(w); }
}Callers expecting Rectangle behavior get surprises—favor composition over forced inheritance.
A strong answer is:
LSP means subtypes must preserve the behavioral contract callers rely on—Square-as-Rectangle violates that, so I model Square independently or use composition.
Explain Interface Segregation and Dependency Inversion.
What interviewers are testing: Whether you keep contracts narrow and make high-level policy independent of concrete infrastructure.
ISP: Clients should not depend on methods they do not use.
// Bad: force read-only repo to implement delete()
interface Repository { void save(); void delete(); }
// Better: split
interface Writer { void save(); }
interface Deleter { void delete(); }DIP: High-level modules depend on abstractions, not concretions.
class OrderService {
private final PaymentGateway gateway; // interface
OrderService(PaymentGateway gateway) { this.gateway = gateway; }
}Dependency injection frameworks such as Spring make DIP easier to implement by wiring abstractions to concrete implementations—see Spring Boot interviews.
A strong answer is:
ISP splits fat interfaces so implementors aren't forced to stub unused methods; DIP injects PaymentGateway interfaces into services so tests swap fakes without changing OrderService.
Design patterns and object-oriented design
Explain creational patterns: Singleton, Factory, Builder.
What interviewers are testing: Whether you can choose a creation pattern because of a real creation problem, rather than name patterns from memory.
| Pattern | Purpose | Interview caution |
|---|---|---|
| Singleton | One instance | Hidden global state; prefer DI |
| Factory / Simple Factory | Centralize object creation and hide concrete classes | Decouples caller from concrete class |
| Builder | Construct an object step-by-step, especially with many optional values | HttpRequest.Builder, custom User.Builder, Lombok @Builder |
interface Notification { void send(); }
class NotificationFactory {
static Notification create(String type) {
return switch (type) {
case "email" -> new EmailNotification();
default -> new SmsNotification();
};
}
}A strong answer is:
Factory hides concrete types; Builder assembles complex objects; Singleton only when one instance is truly required—I prefer Spring-scoped beans over hand-rolled Singletons.
Explain Strategy and Observer patterns.
What interviewers are testing: Whether you can distinguish interchangeable behavior from event publication/subscription.
Strategy: Encapsulate interchangeable algorithms—payment methods, compression codecs.
Observer: One-to-many notification—UI listeners, domain events.
interface PayStrategy { void pay(int cents); }
final class Checkout {
private final PayStrategy strategy;
Checkout(PayStrategy strategy) {
this.strategy = strategy;
}
void checkout(int cents) {
strategy.pay(cents);
}
}Strategy supports OCP—add CryptoPay without editing Checkout internals.
A strong answer is:
Strategy encapsulates interchangeable algorithms behind one interface—Checkout can be configured with Visa, UPI, or another payment strategy without changing Checkout itself; Observer decouples event publishers from subscribers like order-placed emails.
Explain Adapter and Decorator patterns.
What interviewers are testing: Whether you know the difference between changing an interface and layering behavior.
| Pattern | Role | Example |
|---|---|---|
| Adapter | Wrap incompatible API to match expected interface | Legacy LegacyPayment → PaymentGateway |
| Decorator | Add behavior without subclass explosion | BufferedInputStream wrapping FileInputStream |
Decorator avoids subclassing every combination of features; Adapter integrates third-party libraries into your OOP boundaries.
A strong answer is:
Adapter makes legacy APIs fit my interface; Decorator layers behavior—Java I/O streams are the textbook Decorator example I cite in interviews.
How would you design a parking lot system using OOP?
What interviewers are testing: Whether you can whiteboard entities, responsibilities, and patterns for a classic OOD prompt without a god class.
Entities (interview whiteboard approach):
| Class | Responsibility |
|---|---|
ParkingLot |
Floors, entry/exit, availability |
ParkingFloor |
Spots collection |
ParkingSpot |
Size, occupied, vehicle |
Vehicle |
Car, Truck, Motorcycle (type enum or subclass) |
Ticket |
Entry time, spot id |
PricingStrategy |
Interface — hourly, flat |
Use composition: lot HAS floors HAS spots. Use Strategy for pricing. Avoid one ParkingLotManager God class doing payment + SMS + spot math.
A strong answer is:
I identify entities and responsibilities first, use composition for lot/floor/spot ownership, Strategy for pricing, and separate allocation/payment concerns so no single ParkingLot service becomes a god object.
What are common OOP anti-patterns?
What interviewers are testing: Whether you can identify design symptoms and explain an appropriate refactoring direction without applying patterns mechanically.
| Anti-pattern | Problem |
|---|---|
| God object | One class knows everything |
| Anemic domain model | Can be problematic when a genuinely rich domain's business rules are scattered across services; not automatically wrong for simple CRUD/data-transfer models |
| Deep inheritance | Fragile overrides |
| Yo-yo problem | Jump many levels for one method |
| Premature pattern | Factory for one implementation |
Refactor toward small cohesive classes and composition.
A strong answer is:
God classes and deep inheritance hierarchies are red flags—I split responsibilities and inject strategies instead of adding another override layer.
OOP vs functional programming — how do they compare?
What interviewers are testing: Whether you understand that real systems often combine object boundaries with functional transformation styles.
| OOP emphasis | Functional emphasis |
|---|---|
| Encapsulate state and behavior behind object boundaries | Prefer transformations expressed as functions |
| Identity and lifecycle can be important | Immutability and referential transparency are often emphasized |
| Dynamic dispatch/interfaces provide extensibility | Higher-order functions and function composition provide extensibility |
| Mutable state is possible but should be controlled | Side effects are commonly isolated |
Modern Java routinely mixes the two styles—stream().map().filter() is functional style on collections while domain models remain OOP.
A strong answer is:
I use OOP for domain entities with lifecycle and functional style for transformations on immutable data—Java streams don't mean I abandon encapsulation in core models.
What is the difference between a value object and an entity?
What interviewers are testing: Whether you distinguish identity-based entities from value-based objects in domain modeling.
| Entity | Value object | |
|---|---|---|
| Identity | Distinguished by ID even if attributes change | Defined by its values |
| Equality | Same ID → same entity | Same field values → equal |
| Mutability | Often mutable lifecycle | Often immutable |
| Examples | Customer with customerId |
Money, DateRange; Address when identity does not matter in the domain |
Whether something is a value object depends on domain semantics—an address could have identity in some systems. Value objects simplify invariants when defined by values: two Money(10, "USD") instances with the same amount and currency are interchangeable. Entities track continuity over time—a Customer keeps identity after an address change.
A strong answer is:
Entities have identity that persists through change; value objects are compared by value and are often immutable—I'd model Money as a value object and Order as an entity with an order ID.
Final-week OOP interview checklist
Use the final week to rehearse explanations and scenarios—not to memorize every definition.
- Four pillars with one example each
- Encapsulation vs abstraction and data hiding
- Overloading vs overriding + compile vs runtime polymorphism
- Composition vs inheritance + IS-A vs HAS-A
- Abstract class vs interface decision tree
- Diamond problem and Java interface default-method resolution
- Access modifiers table
- SOLID — all five with examples
- Two patterns — Strategy + Factory/Simple Factory or Observer
- One OOD scenario — parking lot or library
- Java part 1 for Java-only follow-ups
- C and C++ if systems role
Pattern cheat sheet (quick reference)
| Need | OOP approach |
|---|---|
| Hide state | Encapsulation + private fields |
| Hide complexity | Abstraction / interface |
| Reuse IS-A behavior | Inheritance (carefully) |
| Reuse HAS-A behavior | Composition |
| Swap algorithms | Strategy pattern |
Create objects without new everywhere |
Factory |
| Many optional features | Decorator or composition |
| Notify many listeners | Observer |
| One class, one job | SRP |
| Extend without editing core | OCP + Strategy |
| Safe subtyping | LSP |
| Testable wiring | DIP + interfaces |
References
Official Java documentation
- Java Language Specification — Classes
- Java Language Specification — Interfaces
- Java Language Specification — Names and Access Control
- OpenJDK JEP 513 — Flexible Constructor Bodies
- Refactoring Guru — Design Patterns
Summary
OOP interviews test whether you can explain why encapsulation and polymorphism matter, when composition beats inheritance, and how SOLID shows up in real code—not recite four pillar names from memory. Use this guide as a self-test: answer aloud and run the polymorphism and composition demos. Pair with Java interviews for language follow-ups and C and C++ interviews when memory and multiple inheritance come up.

