Polymorphism

What is polymorphism in JAVA? How is that achieved?

In JAVA, if any object passes more than one IS A relation, then the object is said to be polymorphic. Any object apart from type Object is polymorphic because it passes at least 2 IS A relations, 1 for its own type and 2 for class Object.

Remember that the only way to access an object is through a reference variable, and there are a few key things to remember about references:

■ A reference variable can be of only one type, and once declared, that type can never be changed (although the object it references can change).

■ A reference is a variable, so it can be reassigned to other objects, (unless the reference is declared final).

■ A reference variable's type determines the methods that can be invoked on the object the variable is referencing.

■ A reference variable can refer to any object of the same type as the declared reference, or—this is the big one—it can refer to any subtype of the declared type!

■ A reference variable can be declared as a class type or an interface type. If the variable is declared as an interface type, it can reference any object of any class that implements the interface.

In JAVA, polymorphism is achieved via Method Overloading (Compile Time Polymorphism) & Method Overriding (Runtime Polymorphism).

What is method overloading? Explain with examples.

Overloaded methods let you reuse the same method name in a class, but with different arguments (and optionally, a different return type).

A method can be overloaded within the same class or in the inherited class.

An important point to remember: The list of arguments is the deciding factor as to which overloaded method will be invoked.

Example 1 : Method overload within same class

class Add{

static int add(int a,int b){return a+b;}

static int add(int a,int b,int c){return a+b+c;}

}

class TestOverloading{

public static void main(String[] args){

System.out.println(Add.add(11,11));

System.out.println(Add.add(11,11,11));

}

}

Output

22

33

Example 2 : Method overload between parent & child class

class Base

{

public int f(int i)

{

System.out.print("f (int): ");

return i+3;

}

}

class Derived extends Base

{

public double f(double i)

{

System.out.print("f (double) : ");

return i + 3.3;

}

}

class myprogram3

{

public static void main(String args[])

{

Derived obj = new Derived();

System.out.println(obj.f(3));

System.out.println(obj.f(3.3));

}

}

Output

f (int): 6

f (double): 6.6

Why is method overloading also called compile time polymorphism?

Let’s review the below piece of code.

class Animal {

}

class Horse extends Animal {

}

class UseAnimal {

public void doSomething(Animal a)

{

System.out.println("In Animal");

}

public void doSomething(Horse h) //doSomething is overloaded

{

System.out.println("In horse");

}

}

public class Test {

public static void main(String[] args) {

UseAnimal UA1 = new UseAnimal();

Animal a1 = new Horse();

Horse h1 = new Horse();

UA1.doSomething(a1);

}

}

     Output: In Animal

Explanation:

In the above example, we have created a Horse object using the Animal reference variable. When we pass that reference to the doSomething() method, because a1 refers to a Horse object, it is tempting to say it will invoke the doSomething() method which takes a Horse object as an argument; but that is not true. It will invoke the doSomething() which takes Animal object, because Method Overloading does happen on compile time.

What is method overriding? Explain with examples.

Whenever a class inherits methods from a superclass, we can override the method. In Method Overriding, we have a huge benefit of implementing the method specific to the child class.

But if a method is declared as Final in super class, that cannot be overridden.

Example –

public class Animal {

public void eat() {

System.out.println("Generic Animal Eating Generically");

}

}

class Horse extends Animal {

public void eat() {

System.out.println("Horse eating hay, oats and horse treats");

}

}

public class Test{

public static void main(String[] args) {

Horse h1 = new Horse();

        h1.eat();

}

}

Output

Horse eating hay, oats and horse treats

Explanation-

In the above program, eat() method is overridden in Horse class. So when we call the eat() method on a horse object, the implementation of eat() in Horse class is executed.

What is Dynamic Method Invocation in JAVA? Or, Why method overriding is known as runtime polymorphism?

Dynamic Method Invocation is the process of determining which version of an overridden method to use based on the actual object (not the reference type) at runtime. That is why method overriding is also referred to as runtime polymorphism.

In the below example, though the reference type is of Animal, the actual object is Horse type object. So, on invoking the eat() method on reference type b, Horse specific eat() method will be invoked, not the eat() method from Animal.

class Animal {

public void eat()

{

System.out.println("Animal eating");

}

}

class Horse extends Animal{

public void eat()

{

System.out.println("Horse eating");

}

}

public class Test {

public static void main(String[] args) {

Animal a = new Animal ();

a.eat();

Animal b = new Horse();

b.eat();

Horse h = new Horse();

h.eat();

}

}

Output

Animal eating

Horse eating

Horse eating

How does polymorphism work together with overloading and overriding?

How does polymorphism work with overloaded methods? From what we just looked at, it doesn't appear that polymorphism matters when a method is overloaded. If you pass an Animal reference, the overloaded method that takes an Animal will be invoked, even if the actual object passed is a Horse. Once the Horse masquerading as Animal gets into the method, however, the Horse object is still a Horse despite being passed into a method expecting an Animal. So it's true that polymorphism doesn't determine which overloaded version is called; polymorphism does come into play when the decision is about which overridden version of a method is called. But sometimes, a method is both overloaded and overridden. Imagine the Animal and Horse classes look like this:

public class Animal {

public void eat() {

System.out.println("Generic Animal Eating Generically");

}

}

public class Horse extends Animal {

public void eat() {

System.out.println("Horse eating hay ");

}

public void eat(String s) {

System.out.println("Horse eating " + s);

}

}

Notice that the Horse class has both overloaded and overridden the eat() method.

What is reference variable casting?

Reference variable casting is assigning a superclass (or Interface) variable to a subclass object or vice versa. Casting is of 2 types, Upcasting & Downcasting.

Upcasting Example

class Animal{

public void eat()

{

System.out.println("Animal eating");

}

}

class Dog extends Animal{

public void eat()

{

System.out.println("Dog eating");

}

public void makeNoise()

{

System.out.println("Dog barking");

}

}

public class Upcasting {

public static void main(String[] args) {

Animal a = new Dog();//Up casting

a.eat(); /*

Compiles fine because compiler sees that Animal class has eat() method, does not complain.But when runs, takes Dog class eat() method*/

((Dog)a).makeNoise();

/*

  * Does not compile until we tell the compiler that Object a is really a Dog's object. So we need to cast it to Dog. */

}

Downcasting Example

class Animal{

public void eat()

{

System.out.println("Animal eating");

}

}

class Dog extends Animal{

public void eat()

{

System.out.println("Dog eating");

}

public void makeNoise()

{

System.out.println("Dog barking");

}

}



public class Downcasting {

public static void main(String[] args) {

Animal a = new Animal

((Dog)a).makeNoise(); //Downcasting

/*

  * Does not compile until we tell the compiler that Object a is really a Dog's object. So we need to cast it to * Dog.*/

}

}

The difference in the above two examples is the actual objects which are created. In the first example, we have created a Dog object, for which calling the makeNoise() method is absolutely fine. Because, the makeNoise() method overrides and JVM looks for the original object (not the reference type) while working with Overriding. So when it finds that it’s really a Dog object, the output is provided.

But in the second example, we are creating an Animal object. Then we have down casted to Dog type. This down casting is fine until the program is in compilation mode, because the compiler does not complain thinking that after downcast, ‘a’ becomes a Dog object. But while JVM runs the program, it finds that ‘a’ is never a Dog object and throws a classcast exception.

To avoid this problem, we can use an instance of operator to make sure that ‘a’ is really a dog object. Here is the improved version of the code:

class Animal{

public void eat()

{

System.out.println("Animal eating");

}

}

class Dog extends Animal{

public void eat()

{

System.out.println("Dog eating");

}

public void makeNoise()

{

System.out.println("Dog barking");

}

}



public class ObjType {

public static void main(String[] args) {

Animal [] a ={new Animal, new Dog, new Animal}

For(Animal a1:a)

{

if(a1 instanceof Dog)

((Dog)a1).makeNoise();

}

Rules for method overloading and overriding

What are the different access modifiers are there in JAVA? 

The access modifiers in Java specifies the accessibility or scope of a field, method, constructor, or class. We can change the access level of fields, constructors, methods, and class by applying the access modifier on it.

Let’s understand the access level of each access modifier using a single table.

What is the usage of ‘super’ and ‘this’ keywords?

The super keyword in java is used to refer immediate parent class object. Whenever we create the object of a subclass, an instance of the parent class is created implicitly and members of the parent instance can be accessed via super keyword.

Usage of Java super Keyword
  • super is used to refer to the immediate parent class instance.
  • variable.super is used to invoke immediate parent class.
  • constructor.super is used to invoke immediate parent class method.
Example 1: Access parent class instance variable

class Vehicle{

int speed=50;

}

class Bike extends Vehicle{

int speed=100;

void display(){

System.out.println(super.speed);

}

public static void main(String args[]){

Bike b=new Bike();

b.display();

}

}

Output

50 // Superclass instance variable is accessed in child class using super keyword.

Example 2: Access parent class constructor

class Vehicle{

Vehicle(){System.out.println("Vehicle is created");}

}

class Bike extends Vehicle{

Bike(){

super();//will invoke parent class constructor

System.out.println("Bike is created");

}

public static void main(String args[]){

Bike b=new Bike();

}

}

Output

Vehicle is created

Bike is created

*** This call to super class constructor is implicit, meaning if we do not include the call; still, it will execute super class constructor before it executes the current class’s constructor.

Example 3: Access parent class method

class Person{

void message(){System.out.println("welcome");}

}

class Student extends Person{

void message(){System.out.println("welcome to java");}

void display(){

message();//will invoke current class message() method

super.message();//will invoke parent class message() method

}

public static void main(String args[]){

Student s=new Student();

s.display();

}

}

Output

welcome to java

welcome

Usage of java this Keyword

  • this is used to refer to the current class instance variable.
  • this is used to refer to the current class constructor.
  • this is used to refer to the current class method.
  • pass current class object reference to a method
Example 1: Access current class instance variable

private String javaFAQ;

void methodName(String javaFAQ) {

this.javaFAQ = javaFAQ; //this refers to instance variable javaFAQ

}

Example 2: Access current class constructor

public class Keywords {

public Keywords(String s)

{

System.out.println("String type args");

}

public Keywords(int i)

{

this("str");// the second constructor is calling the first one, using proper argument.

System.out.println("int type args");

}

public static void main(String[] args) {

new Keywords(5);

}

}

Output

String type args

int type args

Example 3: Access current class method

public class Keywords {

public void m()

{

System.out.println("In first method");

}

public void n()

{

this.m(); //It calls m()

}

public void p()

{

this.n();//It calls n()

}

public static void main(String[] args) {

        (new Keywords()).p();//Final call to m(), sequentially towards top.

}

}

Output

In first method

Example 4: pass current class object reference to a method

public class Keywords {

public void m(Keywords ks)

{

System.out.println("Passing object reference");

}

public void p()

{

  this.m(this); //Passing current class object to method using this keyword

}

public static void main(String[] args) {

(new Keywords()).p();

}

}

Output

Passing object reference

With this article, we have Java OOPs series. Let me know your thoughts and feedbacks in the comment section.


Tags


You may also like

API Basics and Architecture

API Basics and Architecture
Leave a Reply

Your email address will not be published. Required fields are marked

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}