OOPs Concepts
There are 4 main concepts of OOPs. Acronym EAIP represents Encapsulation, Abstraction, Inheritance, and Polymorphism.
- Encapsulation: Encapsulation is the concept of bundling data (attributes) and methods (functions) that operate on the data into a single unit or class. It restricts direct access to some of the object’s components, which is a way of protecting the internal state of the object. Instead of accessing data directly, encapsulation encourages using methods, known as “getters” and “setters,” to retrieve or modify the data.
Information Hiding - Improves Security. Restricts direct access to some of the Object’s data. In Java hiding information is achieved through
"Access Modifiers"
likepublic
,protected
,default
, andprivate
that are used to restrict access to certain data - Abstraction: A
class
in any OOP language is an example of Abstraction. Abstraction is the process of hiding the complex implementation details of a function or an object and showing only the essential features to the user. It allows you to work with higher-level interfaces without needing to know all of the intricate details of how they work internally.Implementation Hiding. Example:
class
, Code written in Declarative Programming Style - Inheritance: Inheritance is a mechanism where one class (child or subclass) inherits attributes and behaviors (methods) from another class (parent or superclass). This promotes code reusability and establishes a relationship between classes. Inheritance allows a subclass to acquire properties and methods from the parent class while also adding its own unique features or overriding inherited behaviors.
IS-A Relationship, Code Reusability
- Polymorphism: Polymorphism allows objects to be treated as instances of their parent class, even if they have unique implementations. This concept enables the same method to perform different behaviors based on the object that is calling it. Polymorphism can be implemented through method overriding (same method name, different behavior in derived class) or method overloading (same method name, different parameters in the same class, depending on the language).
Compile Time Polymorphism( Method Overloading aka static binding doesn’t require inheritance)
-
The method
println()
is an overloaded method injava.io.PrintStream
-
// Overloaded methods of println() public void println(Object x); public void println(String x); public void println(char x); public void println(boolean x); public void println(int x); public void println(long x); public void println(float x); public void println(double x);
Runtime polymorphism(Method Overriding aka dynamic polymorphism requires inheritance)
- The clearest way to express polymorphism is through abstract classes or interfaces.
- Reference StackOverflow answer
-
Example: A slightly modified version of the example from the above citation
-
abstract class Vehicle { String name; Vehicle(String name) { // You can't directly instantiate an abstract class, but this is called from subTypes this.name = name; } void printVehicleInfo() { // concrete method System.out.println("Vehicle name " + name + " and it has got " + getWheels() + " wheels"); } abstract int getWheels(); // abstract method } class Bicycle extends Vehicle { Bicycle(String name) { super("Bicycle"); } @Override int getWheels() { // Overridden method return 2; } } class Car extends Vehicle { Car(String name) { super("Car"); } @Override int getWheels() { // Overridden method return 4; } } class Truck extends Vehicle { Truck(String name) { super("Truck"); } @Override int getWheels() { // Overridden method return 18; } } public class QuickCheck { // This method is an example of polymorphic code static void printVehicleInfo(Vehicle vehicle) { // Program to abstractions vehicle.printVehicleInfo(); // its subtype is resolved at runtime } public static void main(String[] args) { List<Vehicle> vehicles = new ArrayList<>(); // Polymorphic List vehicles.add(new Bicycle("bicycle")); vehicles.add(new Car("Car")); vehicles.add(new Truck("Car")); vehicles.stream().forEach(vehicle -> // Polymorphic call printVehicleInfo(vehicle)); } }
- In the above example
QuickCheck.printVehicleInfo(vehicle)
is polymorphic code, because when you add a new sub type to Vehicle, no need to change this method, because it is written in polymorphic way i.e., programmed to abstractions(meaning reference type is set as abstract class or interfaces). - Also, the subtype of vehicle is resolved dynamically/runtime and appropriate
printVehicleInfo()
method is called. Hence it is known as dynamic/runtime polymorphism.
-
-
References:
- Linkedin learning course
- Programming with Mosh
- Poor Encapsulation example
- Encapsulation and Abstraction
- Abstraction is achieved through interfaces and abstract classes
- An code example talking about Encapsulation and Abstraction in one go
- Reference from SO answer
- Polymorphism reference from SO answer