Polymorphism

5
0

Introduction

Polymorphism is one of the four fundamental principles of object-oriented programming, along with encapsulation, inheritance, and abstraction.

The word polymorphism means “many forms.” In Java, it allows the same method name or parent-class reference to represent different operations and behaviors.

For example, a method named makeSound() may produce different results for a dog, cat, and bird.

Polymorphism

Polymorphism

Java supports two primary types of polymorphism:

  1. Compile-time polymorphism

    • Method overloading

    • Constructor overloading

  2. Runtime polymorphism

    • Method overriding

Why Is Polymorphism Important?

Polymorphism helps developers:

  • Reuse existing code

  • Avoid duplicate logic

  • Create flexible class structures

  • Provide different implementations of a common operation

  • Extend applications without changing large amounts of code

  • Reduce dependencies between classes

  • Improve code readability and maintainability

Compile-Time Polymorphism

Compile-time polymorphism occurs when the compiler determines which method or constructor should be called.

The decision is made according to the arguments supplied in the method or constructor call.

Compile-time polymorphism is also known as:

  • Static polymorphism

  • Early binding

  • Static binding

Java implements compile-time polymorphism through:

  • Method overloading

  • Constructor overloading

Method Overloading

Method overloading means declaring multiple methods with the same name but different parameter lists.

Overloaded methods may differ in:

  • Number of parameters

  • Types of parameters

  • Order of parameter types

Method Overloading Example

// Calculator class containing overloaded methods
class Calculator {
// Adds two integer values
int add(int first, int second) {
return first + second;
}
// Adds two decimal values
double add(double first, double second) {
return first + second;
}
// Adds three integer values
int add(int first, int second, int third) {
return first + second + third;
}
}
// Main class used to execute the program
public class Main {
public static void main(String[] args) {
// Create an object of the Calculator class
Calculator calculator = new Calculator();
// Calls add(int, int)
int integerResult = calculator.add(10, 5);
// Calls add(double, double)
double decimalResult = calculator.add(4.5, 2.5);
// Calls add(int, int, int)
int threeNumberResult = calculator.add(2, 3, 4);
// Display the results
System.out.println(integerResult); // Output : 15
System.out.println(decimalResult); // Output : 7.0
System.out.println(threeNumberResult); // Output : 9
}
}

All three methods are named add(), but their parameter lists are different. The compiler examines the arguments and selects the appropriate method.

Method Overloading

Method Overloading

Constructor Overloading

Constructor overloading means declaring multiple constructors in the same class with different parameter lists.

It allows objects of the same class to be initialized in different ways.

Constructors are not methods, but constructor overloading is considered compile-time polymorphism because the compiler selects the appropriate constructor according to the supplied arguments.

Constructor Overloading Example

// Student class with overloaded constructors
class Student {
// Private attributes of the Student class
private String name;
private int age;
// No-argument constructor
Student() {
// Assign default values
name = "Unknown";
age = 0;
}
// Constructor accepting only the student's name
Student(String name) {
// Store the supplied name
this.name = name;
// Assign a default age
age = 0;
}
// Constructor accepting both name and age
Student(String name, int age) {
// Store the supplied values
this.name = name;
this.age = age;
}
// Display the student's information
void display() {
System.out.println(name + " - " + age);
}
}
// Main class used to execute the program
public class Main {
public static void main(String[] args) {
// Calls the no-argument constructor
Student firstStudent = new Student();
// Calls the constructor accepting a name
Student secondStudent = new Student("Aman");
// Calls the constructor accepting a name and age
Student thirdStudent = new Student("Riya", 20);
// Display the three student objects
firstStudent.display(); // Output : Unknown - 0
secondStudent.display(); // Output : Aman - 0
thirdStudent.display(); // Output : Riya - 20
}
}

The compiler selects one of these constructors based on the arguments used while creating the object.

Constructor Overloading

Constructor Overloading

Runtime Polymorphism

Runtime polymorphism in Java is implemented through method overriding.

It occurs when a child class provides its own implementation of a method inherited from a parent class.

The method that executes is determined by the actual object type at runtime.

Runtime polymorphism is also known as:

  • Dynamic polymorphism

  • Late binding

  • Dynamic binding

  • Dynamic method dispatch

Method Overriding

Method overriding occurs when:

  • A parent class declares an instance method.

  • A child class inherits that method.

  • The child class provides a new implementation with the same signature.

Method Overriding Example

// Parent class representing a general animal
class Animal {
// Method that may be overridden by child classes
void sound() {
System.out.println("The animal makes a sound.");
}
}
// Dog class inherits from Animal
class Dog extends Animal {
// Override the sound() method inherited from Animal
@Override
void sound() {
System.out.println("The dog barks.");
}
}
// Cat class inherits from Animal
class Cat extends Animal {
// Override the sound() method inherited from Animal
@Override
void sound() {
System.out.println("The cat meows.");
}
}
// Main class used to execute the program
public class Main {
public static void main(String[] args) {
/*
* Parent reference containing a Dog object.
* This is called upcasting.
*/
Animal firstAnimal = new Dog();
/*
* Parent reference containing a Cat object.
* This is also an example of upcasting.
*/
Animal secondAnimal = new Cat();
/*
* The object is a Dog, so Dog's sound() method runs.
*/
firstAnimal.sound(); // Output : The dog barks.
/*
* The object is a Cat, so Cat's sound() method runs.
*/
secondAnimal.sound(); // Output : The cat meows.
}
}

Although both variables have the reference type Animal, they contain different child objects.

Animal firstAnimal = new Dog();
Animal secondAnimal = new Cat();

Java checks the actual object type at runtime and calls the corresponding overridden method.

Method Overriding

Method Overriding

Rules for Method Overriding

When overriding a method:

  • A parent-child relationship must exist.

  • The method name must remain the same.

  • The parameter list must remain the same.

  • The return type must be the same or covariant.

  • The child method cannot use a more restrictive access modifier.

  • A final method cannot be overridden.

  • A private method cannot be overridden because it is not inherited.

  • Static methods are hidden, not overridden.

  • Constructors cannot be overridden.

  • The @Override annotation should be used.

Difference between Method Overloading and Method Overriding

Feature

Method Overloading

Method Overriding

Polymorphism type

Compile-time

Runtime

Relationship required

Usually within one class

Parent-child relationship

Method name

Same

Same

Parameters

Must be different

Must be compatible with the inherited method

Return type

May differ when parameter lists differ

Same or covariant

Selection occurs

During compilation

During execution

Main purpose

Provide multiple ways to perform an operation

Provide specialized child behavior

Summary

Polymorphism means “many forms” and allows the same method name or parent-class reference to represent different behaviours. Java supports compile-time polymorphism through method and constructor overloading, where the compiler selects the appropriate version based on the arguments.

Runtime polymorphism is achieved through method overriding, where a child class provides its own implementation of a parent method. The actual object type determines which overridden method runs, making code more flexible, reusable, and maintainable.

CS Core

Read Similar Blogs

Comments0