Compile-Time Polymorphism in Java

Naveen AnamaneniUpdated · 3 min read
mediumJava 25javaooppolymorphism

When the compiler can work out exactly which method a call refers to while compiling, the decision is made once and written into the .class file. That's compile-time polymorphism, also called static polymorphism or early binding. In Java, it comes from method overloading (and constructor overloading): one name, several forms, and the compiler picks the form from the argument types.

The Compiler Picks the Form

Areas.java▶ Try it
public class Areas {
    static double area(double radius) {
        return Math.PI * radius * radius;
    }
 
    static double area(double length, double width) {
        return length * width;
    }
 
    static long area(long side) {
        return side * side;
    }
 
    public static void main(String[] args) {
        System.out.printf("%.2f%n", area(2.0));
        System.out.println(area(3.0, 4.5));
        System.out.println(area(5L));
        System.out.println(area(5));
    }
}
Output
12.57
13.5
25
25

How it works

  1. area(2.0) has one double argument: the circle version.
  2. area(3.0, 4.5) has two: the rectangle version.
  3. area(5L) has a long: the square version.
  4. area(5) passes an int. No area(int) exists. int can widen to long and to double, so both one-parameter methods match. The compiler picks the most specific: long, because a long can widen to double but not the other way round. So the square version runs, which may surprise you.

Try it yourself: add static int area(int side). Which method does area(5) call now?

Forms of Compile-Time Polymorphism in Java

FormExample
Method overloadingarea(double), area(double, double)
Constructor overloadingnew Account("Navika") and new Account("Navika", 5000)
Built-in operator overloading+ adds numbers but joins strings: 2 + 3 vs "Rs. " + 5

Java doesn't let you overload operators for your own classes (unlike C++). The + for strings is built into the language.

Common Mistakes

Thinking overloading is runtime polymorphism. The overload is fixed by the compiler; only overriding is resolved at runtime.

Being surprised by widening. area(5) calling area(long) is correct; add an exact area(int) if you need different behavior.

Overloading with similar types for different jobs. area(long) meaning "square" and area(double) meaning "circle" is confusing; names like squareArea and circleArea are clearer.

Under the Hood

javap -c shows the decisions already made in the bytecode. Each call names one exact method, with its parameter types (D is double, J is long):

javap -c Areas (trimmed)
        14: invokestatic  #21                 // Method area:(D)D
        34: invokestatic  #43                 // Method area:(DD)D
        46: invokestatic  #52                 // Method area:(J)J
        58: invokestatic  #52                 // Method area:(J)J

The last line is the call area(5): the compiler converted the int and fixed the target to area(long). Nothing is looked up at runtime.

Practice

  1. Easy: Write overloaded describe(int), describe(String) and describe(boolean) methods and call each one.
  2. Harder: Compile Areas.java with javac, run javap -c Areas, and find the invokestatic line for each call in main.

Quick check: Compile-time polymorphism

4 questions
1Compile-time polymorphism in Java is achieved by:
2With area(long) and area(double), area(5) calls:
3Can you overload + for your own class in Java?
4Another name for compile-time polymorphism is:

Key Takeaways

Was this tutorial helpful?

Lesson 128 of 482