OOPS Interview Questions and Answers
Preparing for a technical interview? OOPS is a core topic tested across languages like Java, C++, and Python.
Interviewers assess your understanding of concepts such as encapsulation, abstraction, inheritance, and polymorphism, along with their practical implementation.
This guide on OOPS interview questions and answers provides structured, interview-focused questions categorized by difficulty level to help you revise concepts quickly and confidently.
OOPS Interview Questions for Freshers
1. Explain the four main principles of Object-Oriented Programming with examples.
Object-Oriented Programming is based on four core principles that help structure and manage software effectively.
Encapsulation – Bundling data and methods inside a class and restricting direct access to internal variables.
- Example: A BankAccount class keeps balance private and provides deposit() and withdraw() methods.
Abstraction – Hiding implementation details and showing only essential functionality.
- Example: A Car class provides a start() method without exposing engine logic.
Inheritance – Allowing one class to acquire properties and behavior of another class.
- Example: SavingsAccount extends BankAccount.
Polymorphism – Allowing objects to take multiple forms.
- Example: A Shape class with an overridden draw() method in Circle and Rectangle.
2. Differentiate between class and object.
| Feature | Class | Object |
| Definition | Blueprint for creating objects | Instance of a class |
| Memory Allocation | No memory allocated | Memory allocated at runtime |
| Example | class Car {} | Car c = new Car(); |
| Purpose | Defines properties and methods | Uses defined properties and methods |
A class defines structure, while an object represents a real entity created from that structure.
3. How does encapsulation improve code security and maintainability?
Encapsulation protects data by restricting direct access and exposing it through controlled methods.
It improves security by:
- Preventing unauthorized modification of variables.
- Allowing validation inside setter methods.
It improves maintainability by:
- Keeping internal implementation hidden.
- Allowing internal changes without affecting external code.
- Reducing tight coupling between components.
Example:
class Account {
private double balance;
public void deposit(double amount) {
if (amount > 0) balance += amount;
}
}
4. Compare abstraction and encapsulation.
| Feature | Abstraction | Encapsulation |
| Focus | Hides implementation details | Hides internal data |
| Implementation | Abstract classes, interfaces | Access modifiers |
| Purpose | Simplifies complexity | Protects data integrity |
| Example | Interface with method definitions | Private variables with getters/setters |
Abstraction focuses on what an object does, while encapsulation focuses on how data is protected.
5. What is inheritance? Explain different types of inheritance.
Inheritance allows a class to acquire properties and methods from another class, promoting code reuse.
Common types of inheritance:
- Single Inheritance – One child class inherits from one parent class.
- Multilevel Inheritance – A class inherits from a class which itself inherits from another class.
- Hierarchical Inheritance – Multiple child classes inherit from a single parent.
- Multiple Inheritance – A class inherits from more than one parent (supported in C++, achieved using interfaces in Java).
Example:
class Animal { void eat() {} }
class Dog extends Animal { void bark() {} }
6. What is polymorphism? Differentiate between compile-time and runtime polymorphism.
Polymorphism allows the same method name to behave differently based on context.
| Feature | Compile-Time Polymorphism | Runtime Polymorphism |
| Also Known As | Method Overloading | Method Overriding |
| Binding Time | Compile time | Runtime |
| Decision Based On | Method signature | Object type |
| Example | add(int, int) and add(double, double) | Overridden method in subclass |
Compile-time polymorphism is resolved during compilation, while runtime polymorphism is resolved during execution using dynamic binding.
7. How does method overloading differ from method overriding?
| Feature | Method Overloading | Method Overriding |
| Definition | Same method name, different parameters | Redefining parent method in child |
| Occurs In | Same class | Parent and child class |
| Binding | Compile time | Runtime |
| Return Type | May vary (with parameter change) | Must match parent method |
| Access Modifier | No strict restriction | Cannot reduce visibility |
Overloading increases method flexibility, while overriding enables runtime polymorphism.
8. What is a constructor? Can a constructor be overloaded?
A constructor is a special method used to initialize objects when they are created. It has the same name as the class and does not have a return type.
Yes, constructors can be overloaded by defining multiple constructors with different parameter lists.
Example:
class Student {
Student() {}
Student(String name) {}
}
Constructor overloading allows flexible object initialization.
9. What is the difference between an abstract class and an interface?
| Feature | Abstract Class | Interface |
| Method Type | Can have abstract and concrete methods | Typically abstract methods |
| Variables | Can have instance variables | Only constants (by default) |
| Multiple Inheritance | Not supported | Supported |
| Constructor | Can have constructor | Cannot have constructor |
| Use Case | Shared base class | Defining capability contract |
Abstract classes are used when classes share common behavior, while interfaces define contracts that multiple classes can implement.
10. Why is data hiding important in OOPS?
Data hiding restricts direct access to internal object data using access modifiers like private and protected.
Its importance includes:
- Protects sensitive information.
- Prevents accidental modification.
- Ensures controlled access through methods.
- Improves modularity and maintainability.
- Supports secure and robust design.
Example: Keeping password fields private in a User class ensures they cannot be modified directly from outside the class.
11. Write a simple class to represent a BankAccount with deposit and withdraw methods.
class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
balance = initialBalance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
public double getBalance() {
return balance;
}
}
This example demonstrates encapsulation by keeping balance private and allowing controlled access through public methods.
12. What will be the output of a program where a subclass overrides a method of its parent class?
When a subclass overrides a method, runtime polymorphism ensures that the child class method is executed if the object is of the child type.
Example:
class Animal {
void sound() {
System.out.println(“Animal makes a sound”);
}
}
class Dog extends Animal {
void sound() {
System.out.println(“Dog barks”);
}
}
public class Test {
public static void main(String[] args) {
Animal obj = new Dog();
obj.sound();
}
}
Output:
Dog barks
Even though the reference type is Animal, the overridden method in Dog is executed because of dynamic binding.
13. Write a program to demonstrate method overloading.
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
public static void main(String[] args) {
Calculator c = new Calculator();
System.out.println(c.add(5, 3));
System.out.println(c.add(5.5, 3.2));
}
}
Method overloading allows multiple methods with the same name but different parameter types. The compiler decides which method to call based on arguments.
14. Write a simple example to demonstrate runtime polymorphism using inheritance.
class Shape {
void draw() {
System.out.println(“Drawing shape”);
}
}
class Circle extends Shape {
void draw() {
System.out.println(“Drawing circle”);
}
}
public class Demo {
public static void main(String[] args) {
Shape s = new Circle();
s.draw();
}
}
Output:
Drawing circle
Here, the method call is resolved at runtime based on the object type, demonstrating runtime polymorphism.
15. How do access modifiers affect inheritance?
Access modifiers determine how members of a class are accessible in subclasses.
- public – Accessible everywhere, including subclasses.
- protected – Accessible within the same package and in subclasses.
- default (no modifier) – Accessible only within the same package.
- private – Not accessible directly in subclasses.
Private members are not inherited directly but can be accessed through public or protected methods.
16. What is the difference between stack memory and heap memory in OOPS?
| Feature | Stack Memory | Heap Memory |
| Stores | Method calls, local variables | Objects and instance variables |
| Allocation | Automatic | Manual (via new keyword) |
| Lifetime | Ends when method exits | Until object is garbage collected |
| Speed | Faster access | Slower compared to stack |
| Memory Size | Limited | Larger than stack |
Stack memory manages execution flow, while heap memory stores objects created at runtime.
17. What happens when an object is created in memory?
When an object is created using the new keyword:
- Memory is allocated in the heap.
- Instance variables are initialized (default or assigned values).
- Constructor is executed.
- A reference variable in stack memory points to the heap object.
Example:
Student s = new Student();
Here, s is stored in stack memory and refers to the object stored in heap memory.
18. What is the role of the “this” keyword?
The this keyword refers to the current object of a class.
It is used to:
- Differentiate instance variables from local variables.
- Call current class constructor.
- Pass current object as a parameter.
- Return the current instance.
Example:
class Student {
int age;
Student(int age) {
this.age = age;
}
}
Here, this.age refers to the instance variable.
19. Can constructors be inherited? Why or why not?
Constructors are not inherited because they are used to initialize the specific class in which they are defined.
However, a subclass can call a parent constructor using super().
Example:
class Parent {
Parent() {
System.out.println(“Parent constructor”);
}
}
class Child extends Parent {
Child() {
super();
System.out.println(“Child constructor”);
}
}
Constructors ensure proper initialization hierarchy but are not inherited like methods.
20. Why does OOPS promote code reusability?
OOPS promotes code reusability through inheritance, composition, and modular design.
- Inheritance allows reuse of existing class functionality.
- Polymorphism enables flexible and extensible design.
- Encapsulation ensures modular components.
- Design patterns encourage reusable architecture.
Example: A base Vehicle class can be extended by Car, Bike, and Truck, reusing common logic without rewriting code.
OOPS Interview Questions for Intermediate
1. Explain the concept of dynamic binding with an example.
Dynamic binding, also known as late binding, refers to resolving method calls at runtime instead of compile time. The method that gets executed depends on the object type, not the reference type.
It enables runtime polymorphism.
Example:
class Animal {
void sound() {
System.out.println(“Animal sound”);
}
}
class Cat extends Animal {
void sound() {
System.out.println(“Cat meows”);
}
}
public class Test {
public static void main(String[] args) {
Animal obj = new Cat();
obj.sound();
}
}
Output:
Cat meows
Even though the reference is of type Animal, the method in Cat is executed at runtime.
2. How does method overriding achieve runtime polymorphism?
Method overriding allows a subclass to provide a specific implementation of a method already defined in its parent class.
When a parent class reference points to a child class object, the overridden method in the child class is executed during runtime.
Key conditions for overriding:
Same method name
Same parameters
Same or covariant return type
Cannot reduce access level
Example:
class Vehicle {
void run() {
System.out.println(“Vehicle running”);
}
}
class Car extends Vehicle {
void run() {
System.out.println(“Car running”);
}
}
At runtime, the child class method is selected based on the object type.
3. Compare abstract class and interface with use cases.
| Feature | Abstract Class | Interface |
| Method Types | Abstract and concrete methods | Abstract methods (default and static allowed in modern Java) |
| Variables | Instance variables allowed | Only constants |
| Constructors | Can have constructors | Cannot have constructors |
| Multiple Inheritance | Not supported | Supported |
| Use Case | Common base with shared behavior | Define capability or contract |
Use abstract classes when classes share common implementation. Use interfaces when defining behavior that multiple unrelated classes must implement.
4. What is multiple inheritance? How is it handled in Java?
Multiple inheritance allows a class to inherit from more than one parent class.
Java does not support multiple inheritance with classes to avoid ambiguity and complexity. Instead, Java allows multiple inheritance through interfaces.
Example:
interface A {
void show();
}
interface B {
void display();
}
class C implements A, B {
public void show() {}
public void display() {}
}
Here, class C implements multiple interfaces, achieving multiple inheritance behavior safely.
5. Explain the diamond problem and its solution.
The diamond problem occurs in multiple inheritance when two parent classes inherit from the same base class, and a child class inherits from both, causing ambiguity.
Example structure:
Class A
Class B extends A
Class C extends A
Class D extends B and C
If D calls a method defined in A, it becomes unclear whether B’s or C’s version should be used.
Java avoids this problem by:
- Not allowing multiple inheritance with classes.
- Allowing interfaces with explicit method implementation if ambiguity occurs.
Thus, ambiguity is resolved by forcing the child class to override conflicting methods.
6. What are virtual functions and why are they important?
Virtual functions are methods whose execution is determined at runtime based on the object type.
In C++, functions are made virtual using the virtual keyword. In Java, all non-static methods are virtual by default.
Importance:
- Enable runtime polymorphism
- Allow dynamic method dispatch
- Improve extensibility of applications
- Support flexible design
Without virtual functions, method calls would be resolved at compile time, limiting polymorphism.
7. What is composition? How is it different from inheritance?
Composition is a design technique where one class contains an instance of another class to reuse functionality.
| Feature | Composition | Inheritance |
| Relationship | Has-a | Is-a |
| Coupling | Looser | Tighter |
| Flexibility | High | Limited |
| Code Reuse | Through object references | Through subclassing |
| Example | Car has Engine | Dog is Animal |
Composition allows behavior reuse without creating rigid class hierarchies.
8. When would you prefer composition over inheritance?
Composition is preferred when:
- Relationship is “has-a” rather than “is-a”
- Flexibility is required
- Behavior may change at runtime
- Avoiding deep inheritance hierarchies
- Preventing tight coupling between classes
Example: A Car should contain an Engine object instead of inheriting from Engine.
Composition improves maintainability and scalability.
9. Explain the concept of object cloning.
Object cloning creates a copy of an existing object.
In Java, cloning is done using the Cloneable interface and overriding the clone() method.
Example:
class Student implements Cloneable {
int id;
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Cloning creates a new object with the same values as the original object. It is useful when object creation is expensive or when duplicating state is required.
10. What is the difference between shallow copy and deep copy?
| Feature | Shallow Copy | Deep Copy |
| Object References | Copied as reference | New object created |
| Nested Objects | Shared between copies | Independently copied |
| Performance | Faster | Slower |
| Memory Usage | Less | More |
| Risk | Changes affect both objects | Independent objects |
Shallow copy duplicates only primitive values and references, while deep copy duplicates the entire object graph.
Example: If an object contains another object as a field, shallow copy shares it; deep copy creates a new copy of that internal object.
11. Write a class hierarchy for Shape and implement area calculation using polymorphism.
abstract class Shape {
abstract double area();
}
class Circle extends Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
double area() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
private double length, width;
Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
double area() {
return length * width;
}
}
public class TestShape {
public static void main(String[] args) {
Shape s1 = new Circle(5);
Shape s2 = new Rectangle(4, 6);
System.out.println(s1.area());
System.out.println(s2.area());
}
}
A single reference type Shape can call area() for different objects, and the correct implementation is chosen at runtime.
12. Design a class that demonstrates encapsulation with private variables and getter/setter methods.
class Employee {
private int id;
private String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
if (id > 0) {
this.id = id;
}
}
public String getName() {
return name;
}
public void setName(String name) {
if (name != null && !name.isEmpty()) {
this.name = name;
}
}
}
Encapsulation protects internal data and allows validation through setters before updating values.
13. Write pseudocode for implementing an interface in a payment system.
Interface PaymentMethod:
Method pay(amount)
Class UpiPayment implements PaymentMethod:
Method pay(amount):
Validate UPI ID
Deduct amount
Return success message
Class CardPayment implements PaymentMethod:
Method pay(amount):
Validate card number and OTP
Deduct amount
Return success message
Main:
PaymentMethod pm = new UpiPayment()
pm.pay(500)
pm = new CardPayment()
pm.pay(1000)
This design supports adding new payment types without changing the existing payment flow.
14. How would you prevent method overriding in a subclass?
To prevent method overriding:
- Declare the method as final so subclasses cannot override it.
- Declare the class as final so it cannot be inherited.
Example:
class Parent {
final void show() {
System.out.println(“Cannot override”);
}
}
If the method is final, any attempt to override it in a subclass will cause a compile-time error.
15. Write a small program to demonstrate constructor chaining.
Constructor chaining means calling one constructor from another constructor in the same class or calling a parent constructor.
class Parent {
Parent() {
System.out.println(“Parent constructor”);
}
}
class Child extends Parent {
Child() {
super();
System.out.println(“Child constructor”);
}
}
public class Test {
public static void main(String[] args) {
Child c = new Child();
}
}
Output:
Parent constructor
Child constructor
The parent constructor executes first, then the child constructor.
16. What are SOLID principles in OOPS?
SOLID is a set of design principles that helps build maintainable and scalable object-oriented systems.
- S Single Responsibility Principle
- O Open/Closed Principle
- L Liskov Substitution Principle
- I Interface Segregation Principle
- D Dependency Inversion Principle
These principles reduce coupling, improve readability, and make systems easier to extend.
17. Explain the Single Responsibility Principle with example.
Single Responsibility Principle states that a class should have only one reason to change, meaning it should handle only one responsibility.
Example:
Bad design:
- Invoice class handles invoice calculation and also printing.
Better design:
- Invoice class calculates totals.
- InvoicePrinter class prints invoices.
This separation improves maintainability because changes in printing logic do not affect invoice calculation.
18. What is tight coupling and loose coupling?
| Feature | Tight Coupling | Loose Coupling |
| Dependency | High | Low |
| Flexibility | Low | High |
| Change Impact | Changes affect multiple classes | Changes are isolated |
| Testing | Harder to test | Easier to test |
| Example | Class directly creates dependency | Dependency injected via interface |
Loose coupling is preferred because it improves scalability, testing, and maintainability.
19. How does dependency injection relate to OOPS?
Dependency Injection is a technique where an object receives its dependencies from outside rather than creating them internally.
It supports OOPS by:
- Promoting loose coupling
- Improving testability
- Supporting interface-based design
- Aligning with Dependency Inversion Principle
Example: Instead of Car creating an Engine, the Engine is passed into the Car constructor.
This makes the class flexible and easier to modify or test.
20. How do design patterns relate to object-oriented programming?
Design patterns are reusable solutions to common design problems in object-oriented systems.
They help by:
- Improving code structure and readability
- Promoting best practices like loose coupling
- Supporting scalability and maintainability
- Providing proven architectural approaches
Example:
- Factory Pattern creates objects without exposing creation logic.
- Strategy Pattern allows changing behavior dynamically.
Design patterns strengthen OOPS by providing standard ways to apply OOPS principles effectively.
OOPS Interview Questions for Experienced
1. How do SOLID principles improve large-scale application design?
SOLID principles improve scalability, maintainability, and flexibility in enterprise systems by reducing tight coupling and promoting clear separation of concerns.
- Single Responsibility ensures each class has one reason to change, reducing complexity.
- Open/Closed allows adding new features without modifying existing code.
- Liskov Substitution ensures subclasses behave consistently with parent classes.
- Interface Segregation prevents large, unused interfaces.
- Dependency Inversion reduces direct dependency on concrete implementations.
In large-scale systems, these principles make modules independent, testable, and easier to extend without breaking existing functionality.
2. Compare inheritance, composition, and aggregation.
| Feature | Inheritance | Composition | Aggregation |
| Relationship | Is-a | Has-a (strong ownership) | Has-a (weak ownership) |
| Coupling | Tight | Moderate | Looser |
| Lifecycle Dependency | Child depends on parent | Part depends on whole | Independent lifecycle |
| Flexibility | Less flexible | More flexible | More flexible |
| Example | Car is Vehicle | Car has Engine | Team has Players |
Inheritance promotes code reuse through hierarchy. Composition embeds objects strongly. Aggregation represents association where objects can exist independently.
3. How would you refactor a tightly coupled legacy system using OOPS principles?
Refactoring a tightly coupled system involves:
- Identifying classes with multiple responsibilities.
- Applying Single Responsibility Principle.
- Introducing interfaces to abstract dependencies.
- Using dependency injection instead of direct object creation.
- Replacing inheritance misuse with composition.
- Breaking large classes into modular components.
Example: Replace direct instantiation:
Report report = new PDFReport();
With interface-based injection:
Report report = new PDFReport();
generate(report);
This reduces dependency and improves maintainability.
4. Explain Liskov Substitution Principle with a real-world coding example.
Liskov Substitution Principle states that a subclass should be replaceable with its parent class without altering system behavior.
Incorrect example:
class Bird {
void fly() {}
}
class Ostrich extends Bird {
void fly() {
throw new UnsupportedOperationException();
}
}
This violates LSP because Ostrich cannot fly.
Correct approach:
class Bird {}
class FlyingBird extends Bird {
void fly() {}
}
class Ostrich extends Bird {}
class Sparrow extends FlyingBird {}
Now subclasses behave consistently without breaking expectations.
5. What are common violations of OOPS principles in production systems?
Common violations include:
- God classes handling multiple responsibilities.
- Excessive inheritance creating deep hierarchies.
- Hardcoded dependencies instead of interfaces.
- Ignoring encapsulation by exposing internal variables.
- Violating Open/Closed Principle by modifying existing classes for new features.
- Tight coupling between modules.
These issues reduce maintainability and scalability.
6. How does polymorphism improve extensibility in enterprise systems?
Polymorphism allows new implementations without changing existing code.
Benefits:
- Enables adding new subclasses without modifying parent logic.
- Supports Open/Closed Principle.
- Allows interchangeable implementations through interfaces.
- Reduces conditional logic.
Example:
Instead of:
if(type == “CreditCard”) {…}
else if(type == “UPI”) {…}
Use polymorphism:
Payment payment = new CreditCardPayment();
payment.pay();
Adding new payment types requires only new classes.
7. Compare Factory Pattern and Abstract Factory Pattern.
| Feature | Factory Pattern | Abstract Factory Pattern |
| Purpose | Create single product | Create families of related products |
| Complexity | Simpler | More complex |
| Structure | One factory method | Multiple related factory methods |
| Use Case | Creating one object type | Creating multiple related objects |
| Example | Create different Payment objects | Create UI components for different OS |
Factory creates individual objects. Abstract Factory creates groups of related objects without specifying concrete classes.
8. Explain the Strategy Pattern and its practical use case.
Strategy Pattern allows selecting an algorithm at runtime by encapsulating each algorithm inside separate classes.
Structure:
- Strategy interface
- Concrete strategy implementations
- Context class using strategy
Example: Payment processing
interface PaymentStrategy {
void pay(int amount);
}
class CreditCard implements PaymentStrategy {}
class UPI implements PaymentStrategy {}
This allows changing payment method dynamically without modifying core logic.
9. How does the Observer pattern support event-driven design?
Observer pattern defines a one-to-many dependency where changes in one object notify multiple observers automatically.
Key components:
- Subject maintains observer list.
- Observers register with subject.
- Subject notifies observers on state change.
Example: Stock price system notifying traders.
This pattern supports event-driven systems by enabling asynchronous updates and loose coupling between publisher and subscribers.
10. What is the difference between an interface-based design and an implementation-based design?
| Feature | Interface-Based Design | Implementation-Based Design |
| Dependency | Depends on abstraction | Depends on concrete class |
| Flexibility | High | Low |
| Testability | Easy to mock | Harder to test |
| Extensibility | Easy to extend | Requires modification |
| Coupling | Loose | Tight |
Interface-based design promotes loose coupling and scalability. Implementation-based design creates rigid systems that are harder to modify.
11. How does garbage collection work in object-oriented languages?
Garbage collection automatically reclaims memory occupied by objects that are no longer reachable in a program.
In languages like Java:
- Objects are created in heap memory.
- The garbage collector identifies unreachable objects.
- Memory is reclaimed automatically.
- Developers do not manually free memory.
Common GC concepts:
- Mark and Sweep – Marks reachable objects and removes unmarked ones.
- Generational GC – Divides heap into young and old generations for efficient cleanup.
- Stop-the-world pauses – Short pauses during collection.
Example: If an object reference becomes null and no other references point to it, it becomes eligible for garbage collection.
12. Explain object lifecycle in Java or C++.
In Java, the object lifecycle includes:
- Loading – Class is loaded into memory.
- Instantiation – Object created using new.
- Initialization – Constructor initializes variables.
- Usage – Methods are invoked during program execution.
- Garbage Collection – Object becomes eligible for GC when no references exist.
In C++, lifecycle differs:
- Objects may be created on stack or heap.
- Constructor initializes object.
- Destructor is called automatically when object goes out of scope or deleted.
Java relies on garbage collection, while C++ requires explicit memory management for heap objects.
13. What are immutability and its benefits in concurrent systems?
An immutable object cannot change its state after creation.
To create an immutable class:
- Declare class as final.
- Make fields private and final.
- Provide no setters.
- Initialize fields via constructor.
Example:
final class User {
private final String name;
User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Benefits in concurrent systems:
- Thread-safe by default.
- No synchronization required.
- Prevents accidental state modification.
- Improves reliability in multi-threaded environments.
14. How do you design thread-safe classes in OOPS?
Thread safety ensures correct behavior when accessed by multiple threads.
Strategies:
- Use synchronization (synchronized keyword).
- Use immutable objects.
- Use thread-safe collections.
- Apply locks (ReentrantLock).
- Minimize shared mutable state.
- Use atomic variables.
Example:
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
}
The synchronized method prevents race conditions.
15. What are covariant return types?
Covariant return types allow a subclass method to return a more specific type than the return type defined in the parent class.
Example:
class Animal {
Animal getInstance() {
return new Animal();
}
}
class Dog extends Animal {
Dog getInstance() {
return new Dog();
}
}
Here, the overridden method returns a subclass type (Dog), which is allowed in modern object-oriented languages.
16. If a class hierarchy becomes too deep and complex, how would you redesign it?
Deep hierarchies reduce maintainability and flexibility.
Redesign strategies:
- Replace inheritance with composition.
- Extract interfaces for shared behavior.
- Flatten unnecessary levels.
- Apply SOLID principles.
- Use strategy pattern for dynamic behavior.
Instead of:
Class A → B → C → D → E
Use:
- Base interface
- Independent components
- Composition-based relationships
This improves modularity and extensibility.
17. How would you design a plugin-based system using OOPS?
A plugin system allows dynamic extension without modifying core logic.
Design approach:
- Define a common interface (e.g., Plugin).
- Implement concrete plugin classes.
- Use dependency injection or factory pattern.
- Load plugins dynamically at runtime.
Example structure:
interface Plugin {
void execute();
}
class PaymentPlugin implements Plugin {}
class LoggingPlugin implements Plugin {}
The main system interacts with plugins through the interface, enabling easy extension.
18. How would you design a scalable notification system using OOPS principles?
Design considerations:
- Use interface-based design for notification channels.
- Implement strategy pattern for different channels (Email, SMS, Push).
- Use observer pattern for event triggering.
- Separate message formatting from delivery logic.
- Use dependency injection for flexibility.
Example structure:
interface Notification {
void send(String message);
}
class EmailNotification implements Notification {}
class SMSNotification implements Notification {}
This design allows adding new notification types without modifying existing code.
19. How do you ensure backward compatibility when modifying base classes?
Best practices:
- Avoid changing public method signatures.
- Use method overloading instead of modification.
- Mark deprecated methods before removal.
- Follow Open/Closed Principle.
- Maintain interface stability.
Provide default implementations when adding new methods.
This ensures existing subclasses continue functioning without breaking.
20. What trade-offs do you consider when designing reusable frameworks using OOPS?
Key trade-offs include:
- Flexibility vs Complexity – More abstraction increases flexibility but adds complexity.
- Performance vs Extensibility – Highly abstract designs may reduce performance.
- Inheritance vs Composition – Inheritance simplifies reuse but may reduce flexibility.
- Stability vs Innovation – Maintaining backward compatibility can limit rapid changes.
Designing reusable frameworks requires balancing extensibility, maintainability, and simplicity while avoiding over-engineering.
Scenario-Based Questions for OOPS Interviews
1. You are designing a Student Management System. Each student has marks, and marks should not be modified directly from outside the class. How would you design this using OOPS principles?
To solve this, encapsulation should be applied to protect internal data.
Design approach:
- Make instance variables private.
- Provide public getter methods.
- Provide controlled setter methods with validation.
- Avoid exposing internal data structures directly.
Example:
class Student {
private int marks;
public int getMarks() {
return marks;
}
public void setMarks(int marks) {
if (marks >= 0 && marks <= 100) {
this.marks = marks;
}
}
}
This ensures data validation and prevents unauthorized modifications, improving security and maintainability.
2. You need to support multiple payment methods such as Credit Card and UPI in an application. How would you design it so new payment methods can be added later without modifying existing code?
Polymorphism and interface-based design should be used.
Design approach:
- Create a Payment interface.
- Implement separate classes for each payment method.
- Use interface reference in business logic.
Example:
interface Payment {
void pay(double amount);
}
class CreditCardPayment implements Payment {
public void pay(double amount) {
System.out.println(“Paid using Credit Card”);
}
}
class UPIPayment implements Payment {
public void pay(double amount) {
System.out.println(“Paid using UPI”);
}
}
This follows the Open/Closed Principle because new payment types can be added without changing existing classes.
3. A legacy system uses a deep inheritance hierarchy for different types of vehicles. Adding new vehicle types requires modifying multiple parent classes. How would you improve the design?
Deep inheritance causes tight coupling and rigidity.
Improvement strategy:
- Replace inheritance with composition.
- Extract common behaviors into interfaces.
- Use strategy pattern for dynamic behavior like fuel type or drive mechanism.
- Keep base classes minimal.
Instead of:
Vehicle → Car → ElectricCar → SmartElectricCar
Redesign as:
- Vehicle interface
- Engine interface
- DriveStrategy interface
Composition improves flexibility and reduces dependency between classes.
4. Your team reports that changes in one module frequently break another module due to direct object instantiation. How would you redesign this using OOPS principles?
This indicates tight coupling.
Solution approach:
- Introduce interfaces for dependencies.
- Use dependency injection instead of direct instantiation.
- Follow Dependency Inversion Principle.
- Reduce hardcoded object creation.
Instead of:
Report report = new PDFReport();
Use:
Report report = reportFactory.create();
Or inject dependency via constructor:
class ReportService {
private Report report;
ReportService(Report report) {
this.report = report;
}
}
This reduces dependency and improves testability.
5. You are building a large-scale e-commerce platform where different discount strategies (seasonal, membership-based, coupon-based) need to be applied dynamically. How would you design this system using OOPS principles?
The requirement suggests runtime flexibility and extensibility.
Recommended design:
- Use Strategy Pattern.
- Define a DiscountStrategy interface.
- Implement different strategy classes.
- Inject strategy into Order or Checkout class.
Example structure:
interface DiscountStrategy {
double applyDiscount(double amount);
}
class SeasonalDiscount implements DiscountStrategy {
public double applyDiscount(double amount) {
return amount * 0.9;
}
}
class MembershipDiscount implements DiscountStrategy {
public double applyDiscount(double amount) {
return amount * 0.85;
}
}
The Checkout class uses the strategy:
class Checkout {
private DiscountStrategy strategy;
Checkout(DiscountStrategy strategy) {
this.strategy = strategy;
}
double calculateTotal(double amount) {
return strategy.applyDiscount(amount);
}
}
Benefits:
- Follows Open/Closed Principle.
- Easy to add new discount types.
- Avoids large conditional blocks.
- Supports runtime behavior changes.
OOPS MCQ Questions and Answers
Preparing for objective-based rounds is just as important as understanding theoretical concepts in depth. OOPS MCQs help you quickly test your knowledge of core principles such as encapsulation, abstraction, inheritance, polymorphism, constructors, memory management, and design principles.
Practicing multiple-choice questions improves speed, clarity, and accuracy before technical interviews and written tests. You can regularly practice structured OOPS MCQs on PlacementPreparation.io to strengthen your fundamentals and perform confidently in assessment rounds.
Final Words
OOPS concepts form the foundation of modern software development and are frequently tested in technical interviews across languages like Java, C++, and Python. A strong understanding of core principles such as encapsulation, abstraction, inheritance, and polymorphism helps you write structured, maintainable, and scalable code.
Focus on understanding how these concepts are applied in real-world design rather than memorizing definitions. With consistent practice, coding implementation, and revision of interview-focused questions, you can confidently handle OOPS-related interview rounds at any level.
FAQs
The most commonly asked OOPS interview questions focus on the four core principles, differences between abstraction and encapsulation, method overloading vs overriding, constructors, memory management, and SOLID principles.
Freshers should first understand core OOPS concepts clearly and practice writing simple class-based programs demonstrating inheritance, polymorphism, and encapsulation. Solving coding examples and reviewing output-based questions helps build confidence for technical interviews.
Theory questions test conceptual clarity and understanding of principles, while coding-based questions evaluate practical implementation and problem-solving ability.
Yes, SOLID principles are frequently asked in intermediate and experienced-level OOPS interviews because they reflect strong design knowledge. Understanding how these principles improve maintainability and scalability helps you answer architecture-level questions confidently.
OOPS promotes modular, reusable, and maintainable code by organizing programs around objects and responsibilities. It forms the foundation for scalable system design, clean architecture, and modern application development practices.
Related Posts


System Design Interview Questions and Answers
Are you preparing for system design interviews and wondering what kind of architectural questions you might face? System design interviews test …
Warning: Undefined variable $post_id in /var/www/wordpress/wp-content/themes/placementpreparation/template-parts/popup-zenlite.php on line 1050








