Important Concepts of Object-Oriented system (Part IV)

5. Typing

Introduction

It is an enforcement of the class of an object. Different object types will not be normally interchanged and they can be interchanged only in a very controlled manner if required.

Typing is of two types

· Strong Typing or Static typing — In strong typing, operation on an object will be verified at compilation. It enforces type checking (i.e. the process of verifying and enforcing the constraints of types) at compile time.

Ex: — Java, C++

String name = "Shivam"; //variable name is statically typed to 
//String
name = 5;// it will give us compilation error because as name is of
//String type so we can't assign int value in it .

Advantages:

  1. Since, type checking is done at compile time so interpreter or at runtime program can run at full speed, without resolving types.

· Weak Typing or Dynamic typing — In weak typing, messages can be sent to any class. The operation will be verified only during execution or at runtime. It enforces type checking (i.e. the process of verifying and enforcing the constraints of types) at runtime.

Ex: — Perl, Python, JavaScript

Python example :-name = "Shivam"; //variable name is linked to String typename =5;//Here, as we are assigning a integer value, it will become 
//int .

Advantages:

  1. compiler or interpreter implicitly performs certain kinds of type conversions. So applications can be built in a rapid manner.

In weak typing based programming language, more discipline is required because the number of errors or bugs caught at compile time are less than runtime.

Sometimes these above typing types are called Duck typing. It is also considered as sub-set of polymorphism.

In this context, if we will discuss polymorphism then it is a programming technique where we allow multiple types of object to fulfil certain responsibility (i.e. state and behaviour).

But in Java, if we hear the word polymorphism we just relate this concept with the method. Let’s discuss in detail.

Polymorphism: -

Poly + Morphism = different type

It is the ability of an object to take many forms. The possible way to access an object is through the reference variable. The reference variable can be of one type or it can be assigned to other objects that it is not final. The type of reference variable would determine which methods can be invoked.

EX: -

public interface Employee{}
public class Developer{}
public class Manager extends Developer implements Employee{}

Considering the above example we can say that: -

  1. Manager IS-A Developer

So we can write below code since the above statement is correct and all the references refer to the same object Manager.

Manager managerObj = new Manager();
Developer developer = managerObj;
Employee employee = managerObj;
Object object = managerObj;

Above examples are all about typing at the object level.

we can achieve two kinds of polymorphism at the method level, which are as mentioned below: -

  1. Compile time Polymorphism

Compile Time Polymorphism: -

Compile time Polymorphism is achieved by Method Overloading and Operator Overloading.

Method Overloading: Methods with the same name but different signature (i.e. number/type of parameters or Order of parameters) within the same class is called method overloading. The difference in the return type of the overloaded method is not considered.

At compile time, Java compiler knows which method to invoke by checking the method signatures.

//Example of Method Overloading
//Employee.java
package com.thirstybrain.app.polymorphism;public class Employee {public void getEmployeeDetail(String name){
System.out.println("The name of Employee is "+ name);
}
public void getEmployeeDetail(int id){
System.out.println("The id of Employee is "+ id);
}
//Return type of methods don't consider in Method overloading
//after JDK 1.5
}
//Program.javapackage com.thirstybrain.app.polymorphism;public class Program {
public static void main(String[] args) {
Employee emp = new Employee();
emp.getEmployeeDetail(1);
// Output : The id of Employee is 1
emp.getEmployeeDetail("Shivam");
//Output : The name of Employee is Shivam
}
}

The Return type is not part of the method signature and changing only return type creates ambiguity for the compiler to figure out which method to call. That’s why simply changing return type will not be considered as method overloading.
Since binding of method occurs during compile time and calls are resolved at compile time that’s why method overloading is called early binding or static binding.

We can’t able to overload the final method because its implementation already completed that’s why conceptually there is no use of defining another overloaded method of final method.

Some interesting examples: -

//Employee.javapackage com.thirstybrain.app.polymorphism;public class Employee {public void PrintSalary(int salary){
System.out.println("salary from PrintSalary(int salary) method is "+salary);
}
public void PrintSalary(long salary{
System.out.println("salary from PrintSalary(Long salary) method is "+salary);
}public void PrintSalary(double salary){ System.out.println
("salary from PrintSalary(Double salary) method is "+salary);
}public void PrintSalary(Integer salary){
System.out.println("salary from PrintSalary(Integer salary) method is "+salary);
}
}
//Program.javapackage com.thirstybrain.app.polymorphism;public class Program {public static void main(String[] args) {
Employee emp = new Employee();
emp.PrintSalary(1000);
}
}

In the above example

  1. If we will remove “public void PrintSalary(int salary)” then it ‘ll call “public void PrintSalary(long salary)” method.

So the preference hierarchy is given in below format:

Preference order

3. If we’ll pass null while calling PrintSalary method, then it will give compile time error because of ambiguity. It will confuse among the methods which are accepting the argument as int, long and Integer. Since all three types can accept null.

emp.PrintSalary(null);

we can overload main() method but execution always starts from “public static void main(String[] args)”.

Operator Overloading:

The behaviour of an operator to perform multiple functions or operations, then it is termed as operator overloading.

EX: -

//Program.javapackage com.thirstybrain.app.polymorphism;public class Program {public static void main(String[] args) {
String firstName = "Kumar";
String lastName = "Shivam";
System.out.println(firstName+" "+lastName);
//Output: Kumar Shivam
//Here, i'm using "+" operator to do concatenation
int num1 = 10 ;
int sum= num1 + 10 ;
System.out.println(sum);
//Output: 20
//Here, I'm using "+" operator to do Sum
}
}

There are a few rules we should consider while doing operator overloading: -

· If both operands are String, + operator will be used to concatenate.

· If both the operands are int, + operator will be used to add.

· If one operand is int and other is String, then it will do concatenation.

Runtime Polymorphism: -

Runtime Polymorphism is achieved by Method Overriding. A method having the same name and same signature (i.e. number/type/ Order of parameters) but defined in the different inherited class (i.e. parent and child classes).

The class can give its own specific implementation to an inherited method without even modifying the parent class code.

When an overridden method is called the call resolved at runtime that is why it is known as runtime polymorphism or dynamic binding or dynamic method dispatch.

EX: -

//Employee.javapackage com.thirstybrain.app.single;public class Employee {public void getEmployeeDetail(){
System.out.println("Invoked getDetail from Employee Class ");
}
}
//FulltimeEmployee.java
package com.thirstybrain.app.single;
public class FulltimeEmployee extends Employee {@Override
public void getEmployeeDetail(){
System.out.println("Invoked getDetail from FulltimeEmployee Class ");
}
}
//Program.java
package com.thirstybrain.app.single;
public class Program {public static void main(String[] args) {
FulltimeEmployee fulltimeEmployeeObj=new FulltimeEmployee();
fulltimeEmployeeObj.getEmployeeDetail();
//Output : Invoked getDetail from FulltimeEmployee Class
Employee emp=new Employee();
emp.getEmployeeDetail();
//Output : Invoked getDetail from Employee Class
Employee emp1=new FulltimeEmployee();
emp1.getEmployeeDetail();
//Output : Invoked getDetail from FulltimeEmployee Class

//Since all the method in java are virtual by default .
// Reference is of Employee(i.e. Parent) class
//but instance if of FulltimeEmployee(i.e. Child) class
//.That’s why it will call getEmployeeDetail() method of
//FulltimeEmployee(i.e. Child)

}
}

The scenario where we can use method override: -

UseCase: Loan method implementation for multiple lenders

Here in the above image, Let’s consider I am creating a banking application and I’m defining a getLoan() method and this application I’m giving to three different banks. All the banks have different policies and they want to enforce those policies. So to make it happen they will override the getLoan() method and write code specific to their policies.

How does JVM handles method overriding internally?

When we analyze bytecode of overridden method call, we can see that compiler generates a constant table where it assigns integer code to every method call along with it also generated integer code for method reference(#Methodref), Class objects (#Class) etc.

bytecode

Bytecode will be the same for each overridden method call. So, people were thinking if both method calls have the same bytecode then how does JVM know which method to call?

At runtime, JVM uses invokevirtual instruction to invoke the overridden method. Operation instruction invokevirtual accepts a pointer to method reference call (i.e. an index into the constant pool) and that method reference again refer to a method name and Class reference. All these references combined, used to get a reference to a method and class in which the method is to be found. This is also mentioned in the JVM specification. It is a similar concept of vtable in C++ to resolve virtual method calls.

Conclusion

Points considered while doing method overriding: -

  1. Method signature always should be the same.

What Next?

We’ll be discussing Concurrency. Impact of concurrency in application designing and its challenges.

Important Concepts of Object-Oriented system (Part I)

Important Concepts of Object-Oriented system (Part II)

Important Concepts of Object-Oriented system (Part III)

Technical Consultant | Passionate about exploring new Technology | Cyber Security Enthusiast | Technical Blogger | Problem Solver