What is the difference between dynamic and static polymorphism in Java?
Categories:
Dynamic vs. Static Polymorphism in Java: A Comprehensive Guide

Explore the core differences between dynamic (runtime) and static (compile-time) polymorphism in Java, understanding method overloading, overriding, and their practical implications.
Polymorphism, a cornerstone of Object-Oriented Programming (OOP), allows objects of different classes to be treated as objects of a common type. In Java, polymorphism manifests in two primary forms: static (compile-time) and dynamic (runtime). Understanding the distinction between these two is crucial for writing flexible, maintainable, and robust Java applications. This article will delve into each type, providing clear explanations and practical code examples.
Static Polymorphism (Compile-Time Polymorphism)
Static polymorphism, also known as compile-time polymorphism or early binding, is resolved during the compilation phase. The Java compiler determines which method to invoke based on the method signature (name, number, and type of parameters). The most common form of static polymorphism is method overloading.
Method Overloading
Method overloading occurs when a class has multiple methods with the same name but different parameter lists. The return type can be the same or different, but it's not part of the method signature for overloading purposes. The compiler uses the number and types of arguments passed during a method call to decide which overloaded method to execute.
class Calculator {
// Method to add two integers
public int add(int a, int b) {
return a + b;
}
// Overloaded method to add three integers
public int add(int a, int b, int c) {
return a + b + c;
}
// Overloaded method to add two doubles
public double add(double a, double b) {
return a + b;
}
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println("Sum of two integers: " + calc.add(5, 10));
System.out.println("Sum of three integers: " + calc.add(1, 2, 3));
System.out.println("Sum of two doubles: " + calc.add(5.5, 10.5));
}
}
Example of method overloading in Java.
classDiagram class Calculator { +add(int a, int b): int +add(int a, int b, int c): int +add(double a, double b): double } Calculator --> main
Class diagram illustrating method overloading in the Calculator
class.
Dynamic Polymorphism (Runtime Polymorphism)
Dynamic polymorphism, also known as runtime polymorphism or late binding, is resolved during the execution phase of a program. This type of polymorphism is achieved through method overriding and inheritance. When an overridden method is called, the Java Virtual Machine (JVM) determines which version of the method (from the superclass or subclass) to execute based on the actual type of the object at runtime, not the reference type.
Method Overriding
Method overriding occurs when a subclass provides a specific implementation for a method that is already defined in its superclass. The method in the subclass must have the same name, return type, and parameter list as the method in the superclass. The @Override
annotation is often used to indicate that a method is intended to override a superclass method, helping to catch potential errors at compile time.
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Cat meows");
}
}
public class PolymorphismDemo {
public static void main(String[] args) {
Animal myAnimal = new Animal();
Animal myDog = new Dog(); // Runtime polymorphism
Animal myCat = new Cat(); // Runtime polymorphism
myAnimal.makeSound(); // Output: Animal makes a sound
myDog.makeSound(); // Output: Dog barks
myCat.makeSound(); // Output: Cat meows
}
}
Example of method overriding and runtime polymorphism.
myDog
and myCat
are declared as Animal
type, the actual method invoked at runtime is determined by the object's true type (Dog
or Cat
). This is the essence of dynamic polymorphism.classDiagram Animal <|-- Dog Animal <|-- Cat class Animal { +makeSound() } class Dog { +makeSound() } class Cat { +makeSound() }
Class diagram showing inheritance and method overriding.
Key Differences and Use Cases
The fundamental difference lies in when the method call is resolved. Static polymorphism is resolved at compile time, offering performance benefits and compile-time safety. Dynamic polymorphism is resolved at runtime, providing flexibility and extensibility, especially in scenarios involving inheritance hierarchies.

Comparison of Static vs. Dynamic Polymorphism
When to Use Which?
- Static Polymorphism (Overloading): Use when you need to perform similar operations on different data types or with varying numbers of arguments within the same class. It simplifies method naming and improves code readability.
- Dynamic Polymorphism (Overriding): Use when you have an inheritance hierarchy and want to provide specific implementations for a common method in subclasses. It's essential for achieving extensibility and allowing new types to be handled uniformly through a common interface or superclass.