OOP Core Principles Interview Questions (original) (raw)
Last Updated : 17 Oct, 2025
OOP Core Principles revolve around four main concepts: Encapsulation, Abstraction, Inheritance and Polymorphism. Together, these principles form the foundation of object-oriented software design. Below are some of the most asked interview questions on core Principles of OOP.
**1. How does Encapsulation differ from Data Hiding and can one exist without the other?
- **Encapsulation: Bundling data (variables) and methods (functions) into a single unit (class).
- **Data Hiding: Restricting direct access to class internals using access modifiers (private, protected, public).
- **Relation: Encapsulation can exist without strict data hiding (e.g., public fields). Data hiding requires encapsulation because hiding is meaningful only inside a class boundary.
2. Explain how Polymorphism improves extensibility in large-scale systems with an example.
Polymorphism means "one interface, many implementations."
- **Polymorphism: Same interface, different implementations.
- **Benefit: Reduces duplication and makes systems more flexible.
**Example:
Java `
interface Payment { void processPayment(); } class CreditCardPayment implements Payment { ... } class UPIPayment implements Payment { ... } class PayPalPayment implements Payment { ... }
`
- A shopping app can process all payments via the Payment interface.
- Adding new payment types doesn’t break existing code.
3. How do Abstraction and Interfaces differ in OOP and when should each be used?
- **Abstraction: Hides implementation details, shows essential features. Implemented via **abstract classes.
- **Interfaces: Define a **contract with no implementation (until Java 8’s default methods).
**When to use:
- **Abstract class: when related classes share behavior but need some customization.
- **Interface: when unrelated classes must guarantee common behavior.
**Example:
abstract class Bird { void eat(); }interface Flyable { void fly(); }implemented byBird,Drone,Airplane.
4. Discuss how Encapsulation can enhance security in distributed OOP applications.
- Encapsulation hides sensitive details (e.g., passwords, tokens) inside classes.
- Access is only through controlled methods (e.g., getters/setters with validation).
- Prevents unauthorized manipulation of transmitted data across networks.
- Ensures integrity in multi-user, distributed environments.
5. Compare “is-a” vs “has-a” relationships in OOP and explain why misuse can lead to poor design.
- Is-a - Inheritance (Dog is-an Animal).
- Has-a - Composition (Car has-an Engine).
- Misuse (e.g., Car inherits Engine) creates tight coupling and poor flexibility.
- Correct distinction ensures cleaner, scalable OOP design.
6. How does polymorphism resolve the problem of “switch case hell” in OOP design?
- Non-OOP code uses switch/if to handle multiple object types -> cluttered and error-prone.
- Polymorphism delegates behavior to objects via overriding.
- Example: Shapes (Circle, Rectangle, Triangle) each implement draw().
- Client just calls shape.draw(), no need for type checks.
- Follows Open/Closed Principle (extendable without modifying existing code).
7. How do abstract classes and interfaces together solve the “multiple inheritance” problem?
- **Abstract classes -> provide partial implementation + shared behavior.
- **Interfaces -> define pure contracts with no implementation.
- Java allows one abstract class + multiple interfaces, avoiding diamond problem.
- **Example: SmartPhone extends AbstractDevice + implements Camera, GPS, MediaPlayer.
- Combines reusability (abstract) with extensibility (interfaces) without conflict.
**8. How does method overriding differ from method overloading in terms of polymorphism?
- **Method Overriding: Achieves runtime polymorphism. For example, Dog and Cat override makeSound() from Animal. The method executed depends on the object type at runtime.
- **Method Overloading: Achieves compile-time polymorphism. For example, print(int x) vs. print(String s) in the same class. The method is chosen during compilation.
Trick: Overriding supports extensibility and dynamic behavior, while overloading improves readability and convenience. Both forms complement each other but serve different use cases in OOP design.
**9. Why is “tight coupling” between classes considered a violation of good OOP practice?
- Tight coupling = one class directly depends on another’s implementation.
- Example: Car creates PetrolEngine inside constructor -> cannot switch to DieselEngine easily.
- Violates Open/Closed Principle (code not open for extension).
- Solution: use abstraction (e.g., Engine interface) + dependency injection.
- Benefits: loose coupling -> better flexibility, reusability, testability, maintainability.
**10. How can improper use of inheritance break encapsulation?
- Inheritance may expose internal details unintentionally.
- Example: if BankAccount has protected balance, SavingsAccount can modify it directly.
- This bypasses business rules (e.g., transaction validation).
- Effect: breaks data hiding and weakens security.
- Better design: keep fields private, expose only controlled methods (deposit(), withdraw()).
11. Can Polymorphism ever cause performance degradation? How can it be optimized?
Yes, polymorphism (especially runtime polymorphism) introduces performance overhead due to dynamic dispatch. Each method call requires looking up the method in a vtable (virtual table), which adds indirection compared to direct function calls. In high-performance systems like gaming engines or real-time trading platforms, this can become costly. Optimizations include:
- Using final methods to allow compiler inlining.
- Preferring composition where possible.
- Applying caching for frequently invoked polymorphic methods.
Note: Thus, while polymorphism improves design flexibility, developers must balance it against performance requirements.
12. In OOP, how can the misuse of abstraction lead to the “God Object” anti-pattern?
Abstraction should simplify systems by exposing only essential details. However, when too much functionality is forced into a single abstract class (e.g., SystemManager with dozens of unrelated responsibilities), it becomes a God Object. This class centralizes too much logic, making it overly complex, hard to maintain and a single point of failure. The principle of high cohesion is violated. Proper abstraction means decomposing responsibilities into multiple smaller, focused classes/interfaces, ensuring modularity and adherence to SRP (Single Responsibility Principle).
13. Why is diamond inheritance problematic and how do languages like Java and C++ handle it differently?
The diamond problem arises when a class inherits from two classes that both inherit from a common superclass. Ambiguity occurs: which parent’s method should be used?
- **C++: Allows multiple inheritance but solves it with virtual inheritance, ensuring only one copy of the shared base class exists.
- **Java: Avoids the issue by disallowing multiple inheritance of classes altogether. Instead, it allows multiple interfaces and if two interfaces provide default methods with the same signature, the implementing class must resolve the conflict explicitly.
Note: This shows how OOP languages balance flexibility vs. safety in inheritance models.
14. Can polymorphism conflict with encapsulation? Give an example.
Yes, Polymorphism encourages method overriding, but if not carefully designed, it may expose internal state-breaking encapsulation. For example, A User class with getPassword() could be overridden in a AdminUser subclass to expose sensitive details (like raw passwords). While polymorphism enables extensibility, it may unintentionally compromise encapsulated data or business rules.
**Solution: Mark sensitive methods as final or rely on composition over inheritance where exposing critical behavior would be dangerous.
15. How do OOP principles affect memory management, especially in inheritance hierarchies?
Inheritance can create memory overhead: every subclass object stores data from its parent along with its own. Deep hierarchies may waste memory if subclasses don’t need inherited fields. Also, runtime polymorphism requires vtable storage for method dispatch. For large-scale systems (e.g., embedded software, IoT), this can impact performance. To optimize:
- Use composition to include only required objects.
- Apply object pooling to reuse instances.
- Flatten hierarchies to avoid unnecessary inheritance depth.
Note: Thus, OOP principles must be applied with awareness of memory and performance trade-offs.
16 Why is “Composition over Inheritance” considered a better design choice in OOP? Explain with an example.
Inheritance allows code reuse but often introduces tight coupling and fragility when the base class changes. Composition, on the other hand, builds functionality by combining smaller, reusable objects, leading to loose coupling and flexibility. For example, instead of making Car inherit from Engine, you compose it:
Java `
class Engine { void start() { System.out.println("Engine starting..."); } } class Car { private Engine engine = new Engine(); void drive() { engine.start(); System.out.println("Car driving..."); } }
`
Here, Car can swap Engine with another implementation without modifying the class hierarchy. This makes composition superior for maintainability and scalability.
17. What is Method Overriding vs Method Hiding? How do advanced OOP languages handle them differently?
- **Overriding: Subclass provides a new implementation of a method defined in the superclass using runtime polymorphism.
- **Hiding: If a static method in a subclass has the same signature as in superclass, it hides the superclass method, resolved at compile-time.
Example:
Java `
class Parent { static void greet() { System.out.println("Hello from Parent"); } } class Child extends Parent { static void greet() { System.out.println("Hello from Child"); } } Parent.greet(); // Output: Hello from Parent Child.greet(); // Output: Hello from Child
`
Languages like C++ don’t allow true static method hiding in the same sense, whereas Java and C# support both overriding (instance methods) and hiding (static methods).
18. What is Reflection in OOP? Why is it powerful but risky?
Reflection is the ability of a program to inspect and modify its own structure at runtime. It allows dynamic access to classes, fields, and methods without knowing them at compile time.
**Example in Java:
Java `
Class<?> c = Class.forName("java.util.ArrayList"); Method[] methods = c.getDeclaredMethods(); for (Method m : methods) System.out.println(m.getName());
`
**Advantages: Used in frameworks like Spring, Hibernate for dependency injection and dynamic proxies.
**Risks:
- Violates encapsulation.
- Slower performance.
- Can introduce security vulnerabilities by exposing private members.
19. Explain Generics in OOP and their impact on code quality.
Generics allow classes and methods to operate on objects of any type while providing compile-time type safety.
**Example in Java:
Java `
List names = new ArrayList<>(); names.add("Alice"); // Type safe, no casting needed
`
**Benefits:
- Avoids runtime
ClassCastException. - Improves readability and reusability.
- Eliminates duplicate code for different types.
**Advanced Use: Generic bounds () enable restrictions on type parameters, ensuring flexibility while maintaining correctness.
20. What is a Design Pattern? Differentiate between Factory and Abstract Factory with example.
A design pattern is a reusable solution to a common problem in software design.
- **Factory Method: Creates objects of a single family. Java `
abstract class Shape { abstract void draw(); } class Circle extends Shape { void draw() {} } class ShapeFactory { Shape createShape() { return new Circle(); } }
`
- **Abstract Factory: Creates families of related objects without specifying exact classes. Java `
interface GUIFactory { Button createButton(); Checkbox createCheckbox(); } class WindowsFactory implements GUIFactory { ... } class MacFactory implements GUIFactory { ... }
`
**Key Difference:
Factory = single product type.
Abstract Factory = multiple product families.
21. Why is the Singleton pattern considered both useful and dangerous in OOP?
The Singleton pattern ensures only one instance of a class exists, providing a global point of access (e.g., Logger, Configuration).
**Useful Because:
- Saves memory by avoiding multiple instances.
- Ensures controlled access to shared resources.
**Dangerous Because:
- Violates Single Responsibility Principle (acts as both data holder and global access provider).
- Difficult to test (global state interferes with unit tests).
- In multithreaded contexts, improper implementation can break thread safety.
Example (Thread-Safe Singleton in Java):
Java `
class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) instance = new Singleton(); } } return instance; } }
`
Thus, Singleton should be used sparingly, replaced by Dependency Injection in modern design.
22. Explain the Adapter vs Decorator Pattern with example.
Both patterns wrap classes, but their intent differs:
- **Adapter: Converts an incompatible interface into a usable one. Java `
class LegacyPrinter { void oldPrint() { System.out.println("Old Print"); } } interface Printer { void print(); } class PrinterAdapter implements Printer { private LegacyPrinter legacy; PrinterAdapter(LegacyPrinter lp) { this.legacy = lp; } public void print() { legacy.oldPrint(); } }
`
- **Decorator: Adds new behavior dynamically without modifying original class. Java `
interface Coffee { String make(); } class BasicCoffee implements Coffee { public String make() { return "Coffee"; } } class MilkDecorator implements Coffee { private Coffee coffee; MilkDecorator(Coffee c) { this.coffee = c; } public String make() { return coffee.make() + " + Milk"; } }
`
Adapter = Compatibility fix.
Decorator = Extend behavior dynamically.
23. What is Multiple Dispatch? How does it differ from Method Overloading/Overriding?
**Multiple Dispatch:
- Multiple dispatch is an OOP mechanism where the method to execute is chosen based on the runtime types of all arguments, not just the calling object.
- Unlike single dispatch (normal OOP), the runtime checks the most specific match across parameters.
- Example: In scientific computing (Julia), add(Matrix, Matrix) and add(Matrix, Scalar) call different methods depending on the argument combination.
**Difference from Overloading and Overriding:
| Feature | Overloading | Overriding | Multiple Dispatch |
|---|---|---|---|
| Resolution | Compile-time | Runtime (single arg) | Runtime (all args) |
| Based on | Method signature | Receiver type | All parameter types |
| Languages | Java, C++ | Java, C++ | Julia, Lisp, Python (libs) |
**Example in Java (Single Dispatch):
Java `
class Shape { void collide(Shape s) { System.out.println("Shape-Shape"); } } class Circle extends Shape { void collide(Shape s) { System.out.println("Circle-Shape"); } } Shape s1 = new Circle(); Shape s2 = new Shape(); s1.collide(s2); // Circle-Shape
`
24. What is a Metaclass? How does it differ from a normal class?
- A class defines behavior for its instances.
- A metaclass defines behavior for classes themselves.
**Example in Python:
Python `
class Meta(type): def new(cls, name, bases, dct): print(f"Creating class {name}") return super().new(cls, name, bases, dct)
class MyClass(metaclass=Meta): pass
`
Output: Creating class MyClass
**Why useful?
- Enforcing design constraints.
- Auto-registering classes.
- Building frameworks (e.g., Django ORM uses metaclasses).
Thus, metaclasses provide meta-programming control, unlike normal classes that control object behavior.
25. **What is the difference between Association, Aggregation, and Composition in OOP?
- **Association: A general relationship, where objects can exist independently. For example,
Teacher<->Student. - **Aggregation (HAS-A): A weaker form of ownership where child can exist independently of parent. For example,
TeamhasPlayers. Players exist outside the team. - **Composition (PART-OF): Strong ownership, child cannot exist without parent. For example,
CarhasEngine. If car is destroyed, engine ceases too.
Association = loose link.
Aggregation = weak ownership.
Composition = strong lifecycle dependency.