The following are my notes on the 4 basic principles of OOP (Object-oriented programming) based on Kunal Kashwaha’s lectures on YouTube (link in the reference section)
The 4 Basic Principles
1. Inheritance
2. Polymorphism
3. Encapsulation
4. Abstraction
Mnemonic to remember the above:
IPEA: I Paid Eighty American (dollars)
Inheritance
Why is inheritance important?
- code reuse because subclasses inherits the variables and methods of superclass.
extends
keyword used in Java to inherit from a parent classParent class (also called Base class or Super class)
public class Animal { private boolean isCarnivore; private int noOfLegs; public Animal(){} public Animal(boolean isCarnivore, String food, int legs){ this.isCarnivore = isCarnivore; this.noOfLegs = legs; } }
Child class (also known as Sub class or Derived class)
public class Cat extends Animal{ private String color; public Cat(boolean isCarnivore, String food, int legs) { super(isCarnivore, food, legs); this.color="White"; } public Cat(boolean isCarnivore, String food, int legs, String color){ super(isCarnivore, food, legs); this.color=color; } }
Example of main program:
public class AnimalInheritanceTest { public static void main(String[] args) { Cat cat = new Cat(true, "milk", 4, "black"); System.out.println("Cat is carnivore?" + cat.isVegetarian()); System.out.println("Cat eats " + cat.getEats()); System.out.println("Cat has " + cat.getNoOfLegs() + " legs."); System.out.println("Cat color is " + cat.getColor()); } } //OUTPUT: Cat is carnivore? true. Cat eats milk. Cat has 4 legs. Cat color is black.
Use cases of the
super
keyword:- To initialize the data members (variables) belonging to the parent class in the constructor of the child class
ex:
// This is the constructor of the Child class public Cat(boolean isCarnivore, String food, int legs) { super(isCarnivore, food, legs); this.color="White"; }
- When the variable name is same,
super
keyword can be used to refer to the data member belonging to the parent class
ex:
super.member
- super( ) always refers to the constructor in the closest superclass.
- If super( ) is not used in child class constructor, then the default or parameterless constructor of each superclass is executed.
Types of inheritances:
Single Inheritance
public class A { ... .. ... }; public class B extends A { ... .. ... };
Multi-level inheritance
public class A { ... .. ... }; public class B extends A { ... .. ... }; public class C extends B { ... ... ... };
Multiple inheritance (not supported by Java)
Hierarchical Inheritance
public class A { ... .. ... }; public class B extends A{ ... .. ... }; public class C extends A { ... .. ... }; public class D extends A { ... .. ... };
Points to remember:
- You can only specify one superclass for any subclass that you create.
- No class can be a parent class of itself.
- Every class has “Object” class as a superclass in Java.
- A superclass variable can be used to reference any object derived from that class.
A parent class’s variable can reference to child class’ object
Parent ref = new Child();
The type of the reference variable—not the type of the object that it refers to, determines what members or functions can be accessed.
// Parent class class Box { private double width; private double height; private double depth; // construct clone of an object Box() { // pass object to constructor this.width = 0; this.height = 0; this.depth = 0; } }
// Child class class BoxWeight extends Box { double weight; // weight of box // construct clone of an object BoxWeight() { // pass object to constructor this.weight = 0; } }
public static void main(String args[]){ Box ref = new BoxWeight(); // In this case ref can access to width, height and depth variables because it is of type BOX // and it cannot access weight. }
Using final
keyword with Inheritance
Use case 1: to Prevent Overriding
To disallow a method from being overridden, specify final as a modifier at the start of its declaration.
Why to use
final
? Methods declared as final
can sometimes provide a performance enhancement because the compiler is free to inline calls to them. Compiler “knows” they will not be overridden by a subclass’ function. This is called early-binding: function call resolved at compile time.Concept of Late-binding: Usually Java resolves calls to methods dynamically, at run time, when final is not used.
Use case 2: to Prevent Inheritance
When a class is declared as
final
, then it cannot be inherited. NOTE: Declaring a class as final implicitly declares all of its methods as final, too.It is illegal to declare a class as both
abstract
and final
since an abstract class is incomplete by itself and it relies on the subclasses to provide complete implementations.Using static
keyword with Inheritance
static means data member doesn’t depend on the object.
Although
static
methods can be inherited, there is no point in overriding them in child classes because the parent class’ method will run even if we try to override it.Polymorphism
Poly: many
morphism: shapes/forms
Two types of polymorphism
- Compile time polymorphism - achieved through method/function overloading
- Dynamic polymorphism - achieved through method/function overriding
1. function overloading
It is possible to define two or more methods within the same class that share the same name as long as the parameter declarations are different.
Java will employ its automatic type conversions only if no exact match is found.
When Java encounters a call to an overloaded method, it simply executes the version of the method whose parameters matches the arguments used in the call.
class Arithmetic{ int cube(int x){ return x*x*x; } double cube(double x){ return x*x*x; } float cube(float x){ return x*x*x; } public static void main(String[] args){ Arithmetic myMultiplication = new Arithmetic(); System.out.println("The cube of 5 is " + myMultiplication.cube(5)); System.out.println("The cube of 5.0 is " + myMultiplication.cube(5.0)); System.out.println("The cube of 0.5 is " + myMultiplication.cube(0.5)); } //OUTPUT The cube of 5 is 125 The cube of 5.0 is 125.0 The cube of 0.5 is 0.125
2. function overriding
Only occurs when the names and the type signatures of the two methods are identical.
In a class hierarchy, when a method in a child class has the same name and type signature as a method in its parent class, then the child class method overrides the parent class method.
When an overridden method is called from within the same child class, it will always refer to the version of that method defined by the child class.
Dynamic Method Dispatch:
Dynamic method dispatch is the mechanism by which a call to an overridden method is resolved at run time (and not compile time)
When an overridden method is called through the parent class’s reference, Java determines which version of that method to execute based on the type of the object being referred to at the time the call occurs.
In this case, it is the type of the object being referred to (not the type of the reference variable) that determines which version of an overridden method will be executed.
Encapsulation vs Abstraction
Encapsulation | Abstraction |
Hides the code and data into a single entity or unit so that data can be protected from the outside world | Hides unnecessary detail but shows essential information to the user |
Solves the issue at implementation level | Solves an issue at the design level |
focuses on internal working | focuses on external outlook |
implemented by using access modifiers | implemented using abstract classes and interfaces |
getters and setters are used to hide the data | abstract classes and interfaces used to hide complexities |
process of containing information | process of gaining information |