You are currently viewing Types of Polymorphism in Java : Compile-time vs Runtime

Types of Polymorphism in Java : Compile-time vs Runtime

Introduction

Polymorphism is one of the cornerstones of object-oriented programming (OOP), enabling flexibility, extensibility, and clean code in Java. By allowing objects to take many forms, polymorphism promotes code reuse and adaptability. Understanding the two primary types (compile-time and runtime polymorphism) is essential for anyone seeking to master Java.

Write code for today, but design for tomorrow

1. What is Polymorphism?

The term “polymorphism” comes from Greek, meaning “many forms.” In Java, it refers to the ability of a single interface or method to act differently based on the context. Polymorphism allows the same operation to behave differently on different classes, improving both flexibility and maintainability.

“Polymorphism allows you to program in the general, while executing in the specific.”

2. Compile-time Polymorphism (Static Polymorphism)

Java achieves Compile-time polymorphism through method overloading. The compiler determines which method to execute based on the method signature at compile time. This form of polymorphism enhances code readability and reusability.

// Compile-time polymorphism using method overloading

public class PolymorphismCompileVsRuntimeDemo {
    // Overloaded method for integers
    public int add(int a, int b) {
        return a + b;
    }
    // Overloaded method for doubles
    public double add(double a, double b) {
        return a + b;
    }
}

Explanation:
In the code above, the method add is overloaded with different parameter types. At compile time, Java resolves which method to call based on the argument types. For more details on overloading, visit our guide on method overloading in Java.

3. Runtime Polymorphism (Dynamic Polymorphism)

Java achieves Runtime polymorphism through method overriding. In this case, the Java runtime decides which method to execute based on the actual object type, not the reference type.. This enables Java to support dynamic method dispatch and true OOP principles.

// Runtime polymorphism using method overriding

class Animal {
    public void speak() {
        System.out.println("The animal makes a sound.");
    }
}

class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("The dog barks.");
    }
}

public class PolymorphismCompileVsRuntimeDemo {
    public static void main(String[] args) {
        Animal myAnimal = new Dog(); // Reference is Animal, object is Dog
        myAnimal.speak(); // Outputs: The dog barks.
    }
}

Explanation:
Here, the speak method is overridden in the Dog class. Even though the reference type is Animal, the actual method executed at runtime is the Dog’s implementation. For more on overriding, see our article on method overriding and polymorphism.

4. Key Differences Between Compile-time and Runtime Polymorphism

Understanding the distinction between these two types is vital for effective Java programming:

  • Binding Time: Compile-time polymorphism is resolved by the compiler; runtime polymorphism is resolved during program execution.
  • Implementation: Compile-time uses method overloading; runtime uses method overriding.
  • Flexibility: Runtime polymorphism offers greater flexibility and is fundamental to OOP design patterns.
  • Use Cases: Use compile-time polymorphism for methods performing similar tasks with different parameters. Use runtime polymorphism for generalization and abstraction.

“In programming, flexibility comes from runtime decisions; clarity comes from compile-time rules.”

5. Best Practices and Common Pitfalls

While polymorphism is powerful, you must use it thoughtfully:

  • Avoid excessive overloading: Too many overloaded methods can confuse readers.
  • Override intentionally: Always use @Override annotation for clarity and error prevention.
  • Prefer interfaces and abstractions: They maximize the benefits of polymorphism.

Conclusion

Polymorphism in Java enables developers to write flexible, maintainable, and scalable code. By mastering both compile-time and runtime polymorphism, you unlock the full power of object-oriented design.

Remember,

“Polymorphism lets your code adapt to change—now and in the future.”

Explore related topics such as inheritance and interfaces to continue strengthening your Java skills.

You can find the complete code of this article on GitHub.

Noel Kamphoa

Experienced software engineer with expertise in Telecom, Payroll, and Banking. Now Senior Software Engineer at Societe Generale Paris.