DEV Community

Cover image for Java Runtime Polymorphism Explained: My Learning Journey with Method Overriding
Ebenezer
Ebenezer

Posted on

Java Runtime Polymorphism Explained: My Learning Journey with Method Overriding

Introduction

Hey Folks! 👋

Good Day...

Today’s Java session was one of those classes where multiple concepts suddenly connected together. Initially, I thought Method Overriding was just about writing the same method in a child class. But as we explored deeper, I understood how concepts like Upcasting, Runtime Polymorphism, Dynamic Method Dispatch, Reference Types, and Object Types all work together behind the scenes.

In this blog, I’ll share my key takeaways from today's session and the thought process that helped me understand them.


1. A Class is the Data Type of an Object

One of the first things I learned today was that a class acts as a data type for objects.

For example:

Dog dog = new Dog();
Enter fullscreen mode Exit fullscreen mode

Here:

  • Dog is the class
  • dog is the reference variable
  • new Dog() creates the object

Just like int is a data type for numbers, a class becomes a data type for objects.


2. Defining a Child Object as a Parent Reference

The next interesting concept was:

Animal animal = new Dog();
Enter fullscreen mode Exit fullscreen mode

At first, this syntax looked strange.

Questions that came to my mind:

  • Why are we creating a Dog object?
  • Why is the reference variable Animal?
  • Is Java allowing this?

The answer is yes.

This concept is called Upcasting.

Since every Dog is an Animal, Java automatically allows a child object to be stored inside a parent reference.

Dog → Animal
Enter fullscreen mode Exit fullscreen mode

This conversion happens automatically and is therefore known as Implicit Upcasting.


3. What is Method Overriding?

Method Overriding happens when a child class provides its own implementation of a method already present in the parent class.

Example:

class Animal {

    void makeSound() {
        System.out.println("Animal Sound");
    }
}

class Dog extends Animal {

    @Override
    void makeSound() {
        System.out.println("Bark");
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, the Dog class overrides the makeSound() method of the Animal class.


4. Rules of Method Overriding

One important thing I learned today is that overriding follows strict rules.

The following must remain the same:

  1. Method Name

  2. Number of Parameters

  3. Parameter Data Types

  4. Parameter Order

Example:

void display(String name, int age)
Enter fullscreen mode Exit fullscreen mode

The child class must use the exact same method signature.


5. What About Return Types?

Initially, I assumed return types must always be identical.

That is partially true.

Example:

String getName()
Enter fullscreen mode Exit fullscreen mode

can be overridden by:

String getName()
Enter fullscreen mode Exit fullscreen mode

However, Java also supports something called Covariant Return Types.

Example:

class Animal {

    Animal getAnimal() {
        return new Animal();
    }
}

class Dog extends Animal {

    @Override
    Dog getAnimal() {
        return new Dog();
    }
}
Enter fullscreen mode Exit fullscreen mode

Since Dog is a subclass of Animal, Java allows this override.


6. Why Do We Call Method Overriding Runtime Polymorphism?

This was the most important learning of the session.

Consider:

Animal animal = new Dog();

animal.makeSound();
Enter fullscreen mode Exit fullscreen mode

The compiler only knows:

Animal animal
Enter fullscreen mode Exit fullscreen mode

But the actual object created is:

new Dog()
Enter fullscreen mode Exit fullscreen mode

When the method executes, Java checks the actual object type and calls:

Dog.makeSound()
Enter fullscreen mode Exit fullscreen mode

instead of:

Animal.makeSound()
Enter fullscreen mode Exit fullscreen mode

The method decision happens while the program is running.

That is why it is called Runtime Polymorphism.


7. Reference Type vs Object Type

This concept helped me understand Runtime Polymorphism more clearly.

Example:

Animal animal = new Dog();
Enter fullscreen mode Exit fullscreen mode

Reference Type:

Animal
Enter fullscreen mode Exit fullscreen mode

Object Type:

Dog
Enter fullscreen mode Exit fullscreen mode

Important Rule

Reference Type decides:

Which methods are visible at compile time
Enter fullscreen mode Exit fullscreen mode

Object Type decides:

Which overridden method runs at runtime
Enter fullscreen mode Exit fullscreen mode

This single statement clarified many of my doubts.


8. Dynamic Method Dispatch

When Java executes:

animal.makeSound();
Enter fullscreen mode Exit fullscreen mode

it performs a runtime check.

Java asks:

What object is this reference pointing to?
Enter fullscreen mode Exit fullscreen mode

If the object is Dog:

Dog.makeSound()
Enter fullscreen mode Exit fullscreen mode

is executed.

If the object is Cat:

Cat.makeSound()
Enter fullscreen mode Exit fullscreen mode

is executed.

This mechanism is known as Dynamic Method Dispatch.


9. Why Is It Called Runtime Polymorphism?

Another interesting discussion today was:

Why specifically "Runtime"?

Because objects are created only when the application runs.

Example:

new Dog()
Enter fullscreen mode Exit fullscreen mode

The object memory is allocated during execution.

Since Java determines the actual method implementation using the runtime object, the behavior can only be finalized while the program is running.

Hence the name:

Runtime Polymorphism
Enter fullscreen mode Exit fullscreen mode

10. Practice Exercise

To reinforce these concepts, I implemented an Employee hierarchy.

Employee e1 = new Developer();
Employee e2 = new Tester();

e1.work();
e2.work();
Enter fullscreen mode Exit fullscreen mode

This simple example helped me visualize:

  • Upcasting
  • Method Overriding
  • Dynamic Method Dispatch
  • Runtime Polymorphism

all working together in a single program.


Final Thoughts

Today's session completely changed how I view Method Overriding.

Initially, I thought overriding was just about writing the same method in a child class.

Now I understand that Method Overriding is the foundation of:

  • Runtime Polymorphism
  • Dynamic Method Dispatch
  • Upcasting
  • Flexible Object-Oriented Design

The biggest takeaway for me was:

Reference Type decides what methods can be called. Object Type decides which overridden method gets executed.

That one sentence connected almost every concept we discussed today.


References

  1. https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html

  2. https://docs.oracle.com/javase/tutorial/java/IandI/override.html

  3. https://www.w3schools.com/java/java_polymorphism.asp

  4. https://www.geeksforgeeks.org/runtime-polymorphism-in-java/

  5. https://stackoverflow.com/questions/12129200/difference-between-overloading-and-overriding-in-java

Top comments (0)