OOP stands for Object-Oriented Programming, which is a programming paradigm based on the concept of objects. It allows developers to structure code in a way that mimics real-world objects and their interactions.
In OOP, objects represent entities that have both state (attributes or properties) and behavior (methods or functions). The key principles of OOP help make software more modular, reusable, and maintainable.
These four pillars — Encapsulation, Inheritance, Polymorphism, and Abstraction — are the core principles that guide Object-Oriented Programming, making software design more efficient, flexible, and scalable.
Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that allows a new class (subclass or child class) to inherit the properties and behaviors (fields and methods) from an existing class (superclass or parent class). It promotes code reusability and establishes a hierarchy between the classes.
In Java, single inheritance is supported, meaning a class can inherit from only one superclass. However, through interfaces, Java can simulate multiple inheritance.
Single Inheritance: A subclass inherits from one superclass.
1 | class Animal { |
Multilevel Inheritance: A subclass can inherit from a superclass, and then another subclass can inherit from that subclass, forming a chain.
1 | class Animal { |
Hierarchical Inheritance: Multiple classes can inherit from the same superclass.
1 | class Animal { |
Multiple Inheritance (through interfaces): Java does not allow a class to inherit from multiple classes (no direct multiple inheritance), but a class can implement multiple interfaces.
1 | interface Animal { |
Java does not support multiple inheritance directly through classes due to ambiguity, but it can be achieved through interfaces.
In Java, this
and super
are both keywords that refer to the current instance of a class and its parent class, respectively. They are commonly used in object-oriented programming (OOP) to reference the current object and the parent class, enabling effective inheritance and object construction.
this
Keyword:this
keyword refers to the current instance of the class where it is used. It is commonly used to differentiate between class fields and parameters or to call other constructors in the same class.this
is used to refer to instance variables when there is a name conflict with method parameters.this()
to call another constructor within the same class.this
) to other methods or constructors.super
Keyword:super
keyword is used to refer to the parent class. It is mainly used to call the parent class constructor and access parent class members (fields and methods) that are hidden by the current class.super()
is used to invoke the constructor of the parent class, typically the no-argument constructor or a parameterized constructor.super
is used to access the parent class field.super
can be used to call the method from the parent class.this
and super
:Feature | this |
super |
---|---|---|
Refers to | The current instance of the class. | The parent class (superclass). |
Used for | - Referring to instance variables. | - Calling parent class constructor. |
- Calling another constructor in the same class. | - Accessing parent class members (fields/methods). | |
- Passing the current instance to other methods. | ||
Constructor Usage | this() can call another constructor in the same class. |
super() calls a parent class constructor. |
Field Access | this.field accesses the current class’s field. |
super.field accesses the parent class’s field. |
Method Access | this.method() calls the method in the current class. |
super.method() calls the method from the parent class. |
Initialization Order | this() can be used to chain constructors in the same class. |
super() must be the first statement in a subclass constructor. |
Important : this()
and super()
must be the first statement in a constructor.
The diamond problem is a complication in languages that support multiple inheritance, where a class inherits from two classes that have a common ancestor. This leads to ambiguity about which method of the common ancestor should be invoked.
For example:
1 | class A { |
In the above example, class D inherits from both B and C, both of which have their own show()
method. If an instance of D calls show()
, it’s unclear whether it should call the method from B or C.
Java does not allow multiple inheritance through classes, so this issue does not occur directly. However, multiple inheritance through interfaces is allowed, and Java resolves the diamond problem with the default
methods in interfaces.
If multiple interfaces define a default method with the same signature, the class implementing both interfaces must override the method to resolve the ambiguity.
An interface is a contract that defines a set of abstract methods (methods without a body) that must be implemented by any class that implements the interface. Unlike classes, interfaces cannot have method implementations (except for default and static methods introduced in Java 8).
Syntax of an Interface:
1 | interface Animal { |
In Java 8 and later, interfaces can have default methods with a body. This allows interfaces to provide method implementations, which is particularly useful for extending interfaces without breaking existing code.
1 | interface MyInterface { |
A class that implements this interface can choose to override the defaultMethod()
, but it’s not mandatory.
Interfaces can also have static methods in addition to abstract methods. Static methods in interfaces must be called using the interface name.
1 | interface MyInterface { |
A functional interface is an interface that contains exactly one abstract method. These are used primarily with lambda expressions.
Example:
1 |
|
@FunctionalInterface
annotation is optional but can be used to indicate the intent and enforce the constraint of one abstract method.Aggregation is a “has-a” relationship, where one object owns or contains another object, but the contained object can exist independently of the container object.
Library
class can have many Book
objects, but if the Library
is destroyed, the Books
still exist and can belong to another library or not.Book
) is not controlled by the container (like a Library
).Characteristics of Aggregation:
1 | class Book { |
In this example, a Library
aggregates Book
objects. If the Library
is destroyed, the Book
objects can still exist independently.
Composition is a stronger form of Aggregation. It also represents a “has-a” relationship, but in this case, the contained object cannot exist independently of the container object. When the container object is destroyed, all its contained objects are destroyed as well.
House
has many Room
objects. If the House
is destroyed, the Rooms
are destroyed too, because a Room
cannot exist without a House
.Characteristics of Composition:
1 | class Room { |
In this example, a House
composes Room
objects. If the House
is destroyed, all Room
objects associated with it will also be destroyed. The Room
objects cannot exist without the House
.
Feature | Aggregation | Composition |
---|---|---|
Strength of Relationship | Weak relationship: the contained object can exist independently. | Strong relationship: the contained object cannot exist without the container. |
Lifetime Management | The container doesn’t manage the lifetime of the contained objects. | The container controls the lifetime of the contained objects. |
Example | Library and Book (a book can exist without a library) |
House and Room (a room cannot exist without a house) |
Dependence | Contained object can be shared with other objects. | Contained object is tightly bound to the container object. |
Polymorphism is a key concept in Object-Oriented Programming (OOP), and it literally means “many forms.” In simple terms, polymorphism allows objects of different classes to be treated as objects of a common superclass. The main idea is that the same action can behave differently based on the object it is acting upon. Polymorphism means that the same action can be performed differently based on the object doing it.
1 | class Calculator { |
Here, the method add
is overloaded. The correct version of the method is determined based on the type and number of arguments passed when calling it. This is compile-time polymorphism.
1 | class Animal { |
In this case:
myDog
and myCat
are both of type Animal
, they are referring to objects of different classes (Dog and Cat).sound()
method is overridden in Dog
and Cat
.Dog
or Cat
), not the reference type (Animal
).It refers to the concept of hiding the complex implementation details of an object and exposing only the necessary and relevant features or operations to the outside world.
In simple terms, abstraction is about showing the essential features of an object while hiding the unnecessary details. This allows programmers to focus on what an object does rather than how it does it.
In Java, we can achieve abstraction using:
An abstract class in Java is a class that cannot be instantiated (you cannot create an object directly from it). It may contain abstract methods (methods without a body) and concrete methods (methods with a body). The abstract methods in an abstract class must be implemented by its subclasses unless the subclass is also abstract.
Key Points about Abstract Class:
1 | abstract class Animal { |
Feature | Abstract Class | Interface |
---|---|---|
Purpose | To provide common functionality to subclasses. | To define a contract for implementing classes. |
Methods | Can have both abstract and concrete methods. | Can have only abstract methods (before Java 8), but can have default methods (Java 8+). |
Multiple Inheritance | A class can inherit from only one abstract class. | A class can implement multiple interfaces. |
Constructor | Can have constructors. | Cannot have constructors. |
Access Modifiers | Can have access modifiers like public , private , protected . |
All methods are public by default. |
Fields | Can have instance variables and static fields. | All fields are implicitly public static final . |
Default Method Implementation | Not allowed to have default methods. | Can have default methods (Java 8+). |
When to use | When you want to share code among closely related classes. | When you want to define a contract for classes, without enforcing how the methods are implemented. |
Instantiation | Cannot instantiate directly, but can have constructors. | Cannot instantiate directly. |
Implementation Requirement | Subclasses must implement all abstract methods. | Implementing classes must implement all methods unless they are default methods. |
When to Use an Abstract Class vs an Interface:
It refers to the bundling of data (variables) and methods (functions) that operate on the data into a single unit, i.e., a class. More importantly, it is a concept that helps control access to the data by restricting how it can be modified or accessed.