Your experience on this website will be improved by allowing Cookies.
It's the last day for these savings
Object-Oriented Programming (OOPs) has revolutionized the way we design and develop software. As a cornerstone of modern programming languages like Java, C++, and Python, OOPs concepts are elementary for any aspiring software developer.
To help you prepare for a successful start, we've curated a list of the top 53 OOPs interview questions, along with detailed answers. You will have the knowledge and confidence you need to succeed.
Object-Oriented Programming (OOP) is a programming paradigm centered around the concept of "objects". It can represent real-world entities with both data and behavior.
In OOP, data is structured into classes, which serve as blueprints for creating individual objects. Each object contains attributes (properties) and methods (functions) to define its characteristics and behavior.
The core principles of OOP — encapsulation, inheritance, polymorphism, and abstraction — make modular, reusable, and organized code. Developers can create scalable applications, as each object can operate independently while interacting with others.
The core principles of Object-Oriented Programming (OOP) are:
Encapsulation: Encapsulation is the bundling of data (attributes) and methods (functions) within a class, restricting direct access to some components. It boosts data security and reduces complexity by permitting objects to control their state through public methods, known as getters and setters.
Inheritance: A class (child) inherits attributes and methods from another class (parent). It promotes code reuse and establishes a hierarchical relationship between classes.
Polymorphism: Entities to be represented in multiple forms. Methods are to be used interchangeably based on the object context, such as through method overriding and method overloading. The special point lies in objects being processed in a uniform way while still behaving uniquely.
Abstraction: Abstraction hides complex implementation details from the user, exposing only the necessary components. It answers the "what" rather than the "how," making the code more manageable and reducing the risk of unintended interference.
A class is a blueprint or template that defines the properties (attributes) and behaviors (methods) that objects created from the class will have. It serves as a general model for creating multiple objects with similar characteristics and functionalities. For example, a Car class might define attributes like color, make, and model, along with methods like drive() and stop().
On the other hand, an object is an instance of a class. When a class is instantiated, an object is created, possessing its own set of attribute values and capable of performing behaviors defined by the class. For instance, if the Car class is used to create a specific car, that car object will have specific values for color, make, and model and can perform actions like driving or stopping.
In short, a class defines a type, while an object is an instance of that type.
Encapsulation is the principle of Object-Oriented Programming (OOP). It is bundling data (attributes) and methods (functions) within a single unit, known as a class. It restricts direct access to the class’s internal data and allows manipulation of this data only through specified methods.
This "data hiding" technique maintains control over data integrity and minimizes unintended interference from outside code. It exposes only what’s necessary through public methods (getters and setters) while keeping sensitive data private.
Inheritance in OOP is a mechanism where a class (called the child or subclass) inherits attributes and behaviors (methods) from another class (called the parent or superclass). It promotes code reuse and establishes a relationship between classes.
For example, consider a Vehicle superclass with general attributes like speed and fuel. A Car subclass can inherit these attributes and methods from Vehicle while also adding its specific features, such as number_of_doors.
Polymorphism is the ability of different classes to be treated as instances of the same superclass, so the same operation behaves differently on different classes. Methods take on multiple forms, enhancing flexibility and scalability.
Polymorphism is achieved through two main techniques:
Method Overloading (Compile-time Polymorphism): It occurs when multiple methods in the same class have the same name but different parameters (number or type). The method to be called is determined at compile time-based on the method signature.
Method Overriding (Runtime Polymorphism): When a subclass provides a specific implementation for a method that is already defined in its superclass. At runtime, the method to be called is determined by the object's actual class type.
Abstraction is the concept of hiding the complex implementation details of a system and exposing only the essential features or behaviors to the user. With it, programmers can work with higher-level interfaces rather than dealing with intricate underlying code.
OOP (Object-Oriented Programming) differs from procedural programming in several key ways:
Feature | Object-Oriented Programming (OOP) | Procedural Programming |
Structure | Organized around objects (data + behavior) | Organized around functions and procedures |
Data Management | Data encapsulation within objects | Often uses global data, accessible widely |
Reusability | Supports inheritance, polymorphism, abstraction | Primarily function reuse |
Problem-Solving Approach | Models real-world entities and relationships | Follows a step-by-step approach |
Scalability | Highly flexible and suitable for complex systems | Less adaptable for large, complex systems |
OOP is used because it provides several advantages that make code easier to develop, understand, and maintain:
Modularity: OOP organizes code into independent objects, making it easier to break down and manage complex systems.
Reusability: With features like inheritance, you will reuse existing code, reducing redundancy and saving development time.
Scalability and Flexibility: OOP supports polymorphism and abstraction.
Data Security: Encapsulation in OOP restricts direct access to data.
Improved Maintainability: OOP promotes a clear structure, making code easier to troubleshoot, update, and extend.
The benefits of OOP are:
Code Reusability: Inheritance for classes reuses code from existing classes, saving time and reducing redundancy.
Improved Maintainability: OOP’s modular structure organizes code into classes. So, it's easy to update, debug, and extend.
Data Protection: Encapsulation hides data within objects, preventing unauthorized access and protecting data integrity.
Flexibility: Polymorphism is the ability of the same interface to be used with different implementations.
Real-World Modeling: OOP’s object-based approach closely mirrors real-world entities.
Feature | Class | Object |
Definition | A blueprint or template for creating objects | An instance of a class, representing a specific entity |
Role | Defines attributes and methods for objects | Represents an actual entity with specific values |
Data | Does not hold data, only defines structure | Holds data, as it contains specific values for attributes |
Creation | Defined once in the code | Created from a class using the new keyword (or similar) |
A constructor is a special method in a class that is automatically called when an object is created. Its primary purpose is to initialize the object's attributes and set up any necessary resources or configurations. Constructors typically have the same name as the class and do not have a return type.
A destructor is a method in a class that is automatically called when an object is destroyed or goes out of scope. Its primary purpose is to clean up resources, such as closing files, releasing memory, or other cleanup tasks that are necessary before the object is removed from memory.
Destructors typically have the same name as the class, but with a tilde (~) prefix (e.g., ~ClassName()), and they do not accept parameters or return a value.
The this keyword in OOP refers to the current instance of the class. It is used within a class's methods to refer to the current object that the method is acting upon.
It distinguishes between instance variables and parameters or local variables with the same name.
It permits methods to access or modify the current object’s attributes.
It can be used to call other constructors in the same class (constructor chaining).
The public, private, and protected access modifiers in OOP define the visibility and accessibility of class members (attributes and methods) from other parts of the program.
Access Modifier | Visibility | Use |
public | Accessible from anywhere (within the class, subclass, and outside) | Used for members that need to be accessed by any part of the program |
private | Accessible only within the class it is defined in | Used to protect the internal state of an object and maintain encapsulation |
protected | Accessible within the class, by subclasses, but not by other classes | Used for members that should be accessible to subclasses but hidden from other classes |
Method Overloading is when multiple methods in the same class have the same name but different parameter lists. These differences can be in the type, number, or order of parameters, the method can handle different types of inputs. Method overloading is resolved at compile time, so the compiler determines which method to call based on the provided arguments.
One method name can perform related actions for different input variations without requiring distinct names.
Method Overriding is a feature in object-oriented programming. A subclass provides a specific implementation of a method that is already defined in its superclass. When a method in a subclass has the same name, return type, and parameters as a method in its superclass, the subclass’s version overrides the superclass’s version.
Feature | Method Overloading | Method Overriding |
Definition | Multiple methods with the same name but different parameters within the same class. | Redefining a method in a subclass that has the same name, parameters, and return type as in the superclass. |
Purpose | Achieves compile-time polymorphism by methods perform different tasks based on parameter types or counts. | Achieves runtime polymorphism by a subclass provide a specific implementation of an inherited method. |
Resolution Time | Compile-time | Runtime |
Inheritance Requirement | Not required; can exist within the same class. | Required; must be in both the superclass and subclass. |
Method Signature | Must differ in parameter type, number, or order. | Must match exactly in name, parameters, and return type. |
Static Binding (also called early binding) happens when the method to be called is resolved at compile time. It is associated with final, private, or static methods, as well as overloaded methods. Static binding is efficient but does not support runtime polymorphism.
Dynamic Binding (also called late binding) occurs when the method to be executed is determined at runtime based on the actual object type. Dynamic binding is more flexible but introduces a slight runtime overhead.
A superclass is a class from which other classes (known as subclasses) inherit properties and behaviors. The superclass defines general attributes and methods that can be shared among multiple subclasses.
A subclass is a class that inherits the properties and methods of the superclass, often adding or overriding methods to provide more specific behaviors or attributes that differentiate it from other subclasses. This inheritance relationship helps in code reuse and in creating a hierarchical structure within the program.
Interface specifies a set of methods that a class must implement but does not provide any implementation for these methods. The purpose of an interface is to define a standard way for different classes to interact with each other.
An abstract class is a class that cannot be instantiated on its own and is designed to be a base class for other classes. It may contain a mix of fully implemented methods and abstract methods, which are methods declared without any implementation. Subclasses inherited from an abstract class must give implementations for all its abstract methods unless they are also abstract classes.
An abstract class is best for closely related classes, while an interface promotes consistency across different classes.
Feature | Abstract Class | Interface |
Purpose | Provides a base with shared code and behavior for related classes. | Defines a contract or set of methods for classes, without implementation details. |
Method Implementation | Can have both abstract (unimplemented) and concrete (implemented) methods. | Primarily has abstract methods (without implementation); some languages allow default methods. |
Inheritance | A class can inherit only one abstract class (single inheritance). | A class can implement multiple interfaces (supports multiple inheritance). |
Fields and Properties | Can contain fields (variables) and constructors to define state and behavior. | Typically does not have fields; focuses on method declarations only. |
Use Case | Use when classes share common code and some specific methods to be implemented by subclasses. | Use to define a consistent API or capability across potentially unrelated classes. |
Multiple inheritance is a class that can inherit from more than one superclass. A class inherits attributes and methods from multiple parent classes, combining behaviors and functionalities from each. Multiple inheritance can be beneficial for creating complex relationships but can also introduce challenges, such as the diamond problem, where the inheritance hierarchy leads to ambiguity if multiple parent classes have methods with the same name.
Java does not support multiple inheritance with classes to avoid complexity and ambiguity, particularly due to the diamond problem. However, Java allows a form of multiple inheritance through interfaces. A class in Java can implement multiple interfaces, it adopts behaviors from different sources while avoiding the issues associated with multiple inheritance of classes. Since interfaces in Java do not have states (fields), this approach simplifies combining multiple capabilities without risking conflicts in inherited behavior.
The diamond problem is an ambiguity that arises in multiple inheritance when a class inherits from two classes that both inherit from a common superclass. It makes a "diamond" shape in the inheritance hierarchy, where the bottom-most class can inherit conflicting attributes or methods from the two parent classes. The issue becomes particularly problematic if both parent classes provide different implementations of the same method from the common superclass, leading to ambiguity about which method the subclass should inherit.
Aggregation is a relationship between two classes where one class contains a reference to another class. This relationship implies a "has-a" connection, meaning the containing class can exist independently of the contained class. In aggregation, if the containing object is destroyed, the contained object may continue to exist on its own, as it is not fully dependent on the lifecycle of the container. It contrasts with composition, where the contained objects are entirely dependent on the container.
Aggregation and composition are "has-a" relationships in object-oriented programming.
Feature | Aggregation | Composition |
Relationship Type | Weak relationship | Strong relationship |
Dependency | Contained object can exist independently of container | Contained object depends on container's lifecycle |
Example | A library has books (books can exist without library) | A house has rooms (rooms cannot exist without house) |
"Has-a" Relationship | Yes, but allows independent existence | Yes, but implies dependent lifecycle |
Composition is a design principle where one class is composed of one or more objects from other classes, forming a strong "has-a" relationship. The contained objects are integral parts of the container object, and their lifecycles are tied together. If the containing (parent) object is destroyed, the composed (child) objects are also destroyed, as they cannot exist independently.
Composition is used to create complex types by combining simpler, smaller types. It promotes code reusability, as the behavior and attributes of smaller classes can be combined and reused within different classes.
A virtual function is a function declared in a base class that can be overridden in derived classes. The program can decide at runtime which function implementation to invoke based on the object's actual derived type, even if it’s referenced through a base class pointer or reference.
A pure virtual function is a virtual function in a base class that has no implementation and is meant to be overridden in derived classes. It is declared by assigning = 0 to the function declaration in the base class. A class with at least one pure virtual function is called an abstract class and cannot be instantiated on its own.
Pure virtual functions define a common interface for derived classes, enforcing that each derived class provides its own specific implementation of the function. This approach is fundamental for achieving polymorphism, derived classes have tailored behaviors while sharing a common interface.
The final keyword in Java and the sealed keyword in C# control inheritance, restricting or controlling how classes and methods can be extended.
Java (final keyword): When applied to a class, the final keyword prevents other classes from inheriting it. When applied to a method, it prevents subclasses from overriding it. It is useful for certain behaviors to remain unchanged in derived classes. It is responsible for security, performance, or design reasons.
C# (sealed keyword): The sealed keyword in C# restricts further inheritance of a class or prevents further overriding of a method that is already overridden in a derived class. It improves performance or enforces security and immutability by sealing certain parts of the class hierarchy.
A copy constructor is a constructor that creates a new object as a copy of an existing object. It takes a reference to an object of the same class as a parameter and duplicates its properties into the new instance.
Copy constructors handle cases where an object contains pointers or other resources that need deep copying to avoid unintended shared references. Languages like C++ support custom copy constructors. It means developers define how objects are copied, which is especially important when managing dynamic memory or complex resources.
A friend function is a function that is given special access to the private and protected members of a class, even though it is not a member of that class. Friend functions are declared with the friend keyword within the class they need access to.
The purpose of a friend function is to allow external functions or other classes to access private data without breaking encapsulation. Common use cases for this function are operator overloading, where an external function needs access to a class's private data, or when closely related classes need to work with each other’s internals for efficiency or design reasons. However, friend functions should be used sparingly, as they bypass the usual access control and can lead to tightly coupled code.
Covariance and contravariance describe how the types of objects can vary in hierarchical relationships, particularly in inheritance and method overriding.
Covariance permits a method to return a more specific (derived) type than specified in the base class. It enables flexibility in return types, as a subclass can narrow the return type to a subtype. For example, if a base class method returns an object of type Animal, an overridden method in a derived class could return Dog, a subtype of Animal.
Contravariance - a method that accepts a more general (base) type than specified in the base class. It applies to parameters rather than return types, enabling greater flexibility in method parameters. For example, if a base class method takes a parameter of type Dog, a derived class could override it to accept Animal.
A mixin is a class or a set of functionalities that are intended to be inherited by other classes to add specific, reusable behaviors or properties. Unlike traditional inheritance, where a subclass inherits a base class’s full structure, a mixin allows classes to "borrow" methods and properties from multiple sources.
Dependency Injection (DI) is a design pattern in object-oriented programming. It is used to achieve Inversion of Control (IoC) by injecting dependencies (objects a class relies on) into a class rather than having the class instantiate them itself. This approach decouples the creation and management of dependencies from the classes that use them, promoting flexibility, reusability, and easier testing.
The association represents a relationship between two or more objects where one object is connected to or interacts with another. It is established by linking the objects through their attributes, they work together without one owning or controlling the other. This relationship can vary in direction and strength, from simple references to complex containment.
The SOLID principles are five OOP design guidelines for creating flexible, scalable software.
Single Responsibility Principle (SRP): A class should have only one reason to change, meaning it should be responsible for one task only. It keeps classes focused, making them easier to understand and maintain.
Open/Closed Principle (OCP): Classes should be open for extension but closed for modification. You should add new features by extending existing code, not by altering it.
Liskov Substitution Principle (LSP): Subclasses should be replaceable for their base classes without affecting program behavior. It creates consistent behavior when using polymorphism.
Interface Segregation Principle (ISP): No client should be forced to depend on methods it doesn’t use. Split large interfaces into smaller, specific ones to keep implementations focused.
Dependency Inversion Principle (DIP): High-level modules should depend on abstractions, not on concrete implementations. It reduces coupling and increases flexibility in the code.
The Single Responsibility Principle (SRP) is one of the five SOLID principles in OOP. It states that a class should have only one reason to change, meaning it should be responsible for only one task or functionality.
In practical terms, each class has a single, focused purpose, which makes the code easier to understand, test, and maintain. By separating concerns, SRP also reduces the chance of unintended side effects, as changes in one class won’t impact unrelated functionality.
For example, if you have a Report class, SRP suggests that it should handle report data only, not additional tasks like printing or formatting, which could be delegated to separate classes (e.g., ReportPrinter or ReportFormatter).
The Open-Closed Principle (OCP) states that software entities (such as classes, modules, and functions) should be open for extension but closed for modification.
You should be able to add new functionality to a class without changing its existing code. By adhering to OCP, you avoid altering tested and working code when adding new features.
For example, instead of modifying a base Shape class to add support for new shapes, you would create new subclasses (e.g., Circle, Rectangle) that extend Shape and implement the required functionality, keeping the Shape class unchanged. This approach leverages inheritance and polymorphism to make classes more adaptable and extendable.
The Liskov Substitution Principle (LSP) says that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.
In other words, if a class B is a subclass of class A, then B should be usable wherever A is expected, without causing errors or unexpected behavior. Subclasses extend the functionality of a base class without altering its fundamental behavior.
For example, if Rectangle is a subclass of Shape, you should be able to use Rectangle in any context that expects a Shape, and it should work as expected. Violating LSP often indicates that subclasses are not true extensions of the superclass, potentially leading to unexpected or inconsistent behavior in the application.
The Interface Segregation Principle (ISP) opines that no client should be forced to depend on methods it does not use. It encourages designing smaller, more specific interfaces rather than large, general-purpose ones.
ISP helps to keep classes focused on relevant functionality by allowing them to implement only the methods they actually need. It avoids "fat interfaces" and makes the code more modular and easier to maintain.
For example, instead of creating a large Worker interface with methods like work() and eat(), you might create separate interfaces like Workable and Eatable. This way, a class representing a robot can implement Workable without being forced to implement an unnecessary eat() method.
The Dependency Inversion Principle (DIP) is:
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
In simpler terms, the DIP emphasizes that instead of high-level modules (which define core business logic) relying on low-level modules (which handle specific implementations), both should rely on abstract interfaces or classes. It promotes flexibility and reduces the impact of changes in the system, making the code more modular and easier to maintain or extend.
The Factory Design Pattern is a creational design pattern that has an interface for creating objects in a superclass. Subclasses can alter the type of objects that will be created. Instead of using direct class instantiation, the factory pattern creates objects by calling a factory method, which delegates the creation to subclasses.
The Singleton Design Pattern is a creational design pattern that makes sure a class has only one instance and provides a global access point to that instance. It restricts instantiation of the class to a single object, which can be useful when exactly one object is needed to coordinate actions across a system.
The Observer Pattern is a behavioral design pattern that defines a one-to-many relationship between objects. In this pattern, an object called the subject maintains a list of its dependents, called observers, and notifies them automatically of any state changes.
The Observer Pattern is useful for implementing distributed event-handling systems, where multiple objects need to respond to changes in another object’s state without tight coupling.
In design patterns, the Facade pattern offers a simplified interface to a complex subsystem. It acts as a "front-facing" class that wraps a set of subsystems or components, making it easier to interact with the system as a whole. By using a Facade, clients can perform high-level tasks without needing to understand the intricate workings of each component. It is beneficial for reducing dependencies and improving code readability, as it hides the complexity of the underlying structure from the client.
Memory allocation for objects occurs on the heap, which is a memory area designated for dynamic allocations. When an object is created (using, for example, new in languages like Java and C++), memory is allocated on the heap to store the object's data and metadata, such as instance variables and any references it may contain. The size of the memory block depends on the object's structure and the data it holds.
In many languages, garbage collection or manual memory management is used to deallocate memory when objects are no longer needed. Some languages, like C++, require explicit deletion of objects, while others, like Java, have garbage collectors to automatically free up memory by detecting and removing unused objects.
Garbage collection is an automatic memory management process that reclaims memory occupied by objects no longer in use, preventing memory leaks and optimizing resource usage. In languages like Java, Python, and C#, the garbage collector tracks object references; when an object becomes unreachable (i.e., there are no references to it), it is marked for removal. The garbage collector then frees the memory, making it available for new allocations. This process supports managing memory efficiently without requiring manual deallocation, though it can add slight overhead due to periodic checks for unused objects.
A shallow copy and a deep copy are two ways to duplicate an object, differing in how they handle nested objects (references within the original object).
Shallow Copy: A shallow copy duplicates the object itself but not the objects it references. It copies the top-level properties or fields, but if the object contains references (e.g., lists, other objects), only references are copied, not the actual nested data. Thus, changes to nested objects in the copy will affect the original.
Deep Copy: A deep copy duplicates the object along with all objects it references, recursively copying each layer. It creates a completely independent object, so modifications to nested objects in the copy do not impact the original.
Shallow copies are typically faster but less isolated, while deep copies make full independence at the cost of performance and memory.
Feature | Stack Memory | Heap Memory |
Purpose | Stores local variables and function call information | Used for dynamic memory allocation, stores objects/data that need to persist beyond function scope |
Structure | Last-in, first-out (LIFO) | Unstructured, managed dynamically |
Size | Limited and smaller | Generally larger |
Speed | Fast | Slower |
Management | Automatically managed by system | Manually managed or garbage collected |
Allocation/Deallocation | Automatic with function calls and returns | Manual (or automatic with garbage collection) |
Memory Lifetime | Temporary, tied to function scope | Persists until explicitly freed or collected |
Fragmentation | None, as memory is sequentially allocated | Possible, due to variable allocation sizes |
You should know the fact that many companies rely on OOP principles to create flexible code. Don't be discouraged reviewing these Top 53 OOPs interview questions and detailed answers. When you understand the "why" behind each principle and pattern, you’ll be ready to demonstrate your expertise in OOP during your next interview confidently. Good luck, and happy coding!
If there is still technological knowledge that you do not know where to find, you can refer to Skilltrans courses. We will bring you the most updated and easy-to-understand knowledge.
Meet Hoang Duyen, an experienced SEO Specialist with a proven track record in driving organic growth and boosting online visibility. She has honed her skills in keyword research, on-page optimization, and technical SEO. Her expertise lies in crafting data-driven strategies that not only improve search engine rankings but also deliver tangible results for businesses.