Compile-Time Polymorphism in Java
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
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));
}
}12.57
13.5
25
25How it works
area(2.0)has onedoubleargument: the circle version.area(3.0, 4.5)has two: the rectangle version.area(5L)has along: the square version.area(5)passes anint. Noarea(int)exists.intcan widen tolongand todouble, so both one-parameter methods match. The compiler picks the most specific:long, because alongcan widen todoublebut 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
| Form | Example |
|---|---|
| Method overloading | area(double), area(double, double) |
| Constructor overloading | new 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):
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)JThe 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
- Easy: Write overloaded
describe(int),describe(String)anddescribe(boolean)methods and call each one. - Harder: Compile
Areas.javawithjavac, runjavap -c Areas, and find theinvokestaticline for each call inmain.
Key Takeaways
Was this tutorial helpful?