The term polymorphism can be defined as “having many forms.” A polymorphic reference is a reference variable that can refer to different types of objects at different points in time. The specific method invoked through a polymorphic reference can change from one invocation to the next.
At some point, the commitment is made to execute certain code to carry out a method invocation. This commitment is referred to as binding a method invocation to a method definition. In many situations, the binding of a method invocation to a method definition can occur at compile time. For polymorphic references, however, the decision cannot be made until run time. The method definition that is used is based on the object that is being referred to by the reference variable at that moment. This deferred commitment is called late binding or dynamic binding. It is less efficient than binding at compile time, because the decision must be made during the execution of the program. This overhead is generally acceptable in light of the flexibility that a polymorphic reference provides.
Additionally, we will demonstrate the use of the instance of operator
/* * Polymorphism Late binding */ // Animal class - this is the base class class Animal { public void animalSound() { System.out.println("The animal makes a sound"); } // Regular method public void sleep() { System.out.println("Zzz"); } } //end of Animal Base Class /* ********************************* * Derived Classes *********************************** */ //Subclass (inherit from Animal) //Notice how we define the Abstract method animalSound declared in the super class class Cat extends Animal { public void animalSound() { // The body of animalSound() is provided here System.out.println("The cat says Meow"); } } //end of Cat Class //Subclass (inherit from Animal) class Dog extends Animal { public void animalSound() { // The body of animalSound() is provided here System.out.println("The dog says Woof"); } } //end of Dog class //Subclass (inherit from Animal) class Cow extends Animal { public void animalSound() { // The body of animalSound() is provided here System.out.println("The dog says Moo"); } } /* * ****************************** * Main Program to demo polymorphism * ****************************** */ public class Demo { /** * @param args */ public static void main(String[] args) { Animal myAnimal = new Animal(); // Create a Animal object myAnimal.animalSound(); myAnimal.sleep(); //now create an Animal and make it a Dog Animal myDog = new Dog(); myDog.animalSound(); myDog.sleep(); //now create an Animal and make it a Cat Animal myCat = new Cat(); myCat.animalSound(); myCat.sleep(); Animal myCow = new Cow(); myCow.animalSound(); myCow.sleep(); //demonstration of instanceof if(myCat instanceof Cat) { System.out.println("This is a cat!"); } if(myCat instanceof Animal) { System.out.println("This is a Animal!"); } } }
The given Java code is a demonstration of polymorphism in Java using animal sounds as examples. Polymorphism allows objects to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object.
Let's go through the important parts:
The
Animal
class is the parent (base) class with two methods:animalSound()
andsleep()
.animalSound()
is overridden in each of the child classes whilesleep()
is not, meaning it's the same across all animal types.Cat
,Dog
, andCow
are subclasses that each extendAnimal
. They each override theanimalSound()
method to print out a unique sound for that animal. This is a perfect example of method overriding in Java, which is one of the ways we can achieve polymorphism.In the
main
method, we first create a genericAnimal
object and call its methods. This is standard object-oriented programming.Then we create
Dog
,Cat
, andCow
objects but refer to them withAnimal
references. This is polymorphism in action - we can call theanimalSound()
method on these references and it will call the overridden method in the respective subclass, even though the reference type isAnimal
. This is known as late binding or dynamic method dispatch.The
sleep()
method is also called on these references. Sincesleep()
is not overridden in the subclasses, the originalsleep()
method fromAnimal
class is called.Finally, the
instanceof
keyword is used to check ifmyCat
is an instance ofCat
andAnimal
.instanceof
returns true if the object being compared is an instance of the specified type or an instance of a subclass of the specified type. So, in this case, both checks will return true becausemyCat
is aCat
object andCat
is a subclass ofAnimal
. This is why "This is a cat!" and "This is a Animal!" both get printed.