Polymorphism comes in two forms. The difference is when Java decides which method will run: while the code is being compiled, or while the program is running.
| Kind | Also called | How achieved | Decided |
|---|---|---|---|
| Compile-time | Static binding | Method overloading | By the compiler, from the arguments |
| Run-time | Dynamic binding | Method overriding | By the JVM, from the actual object |
Overloading was covered in 3.1.6; overriding in 3.5.4.
Compile-time polymorphism (overloading)
void print(int x) { System.out.println("int: " + x); }
void print(String s) { System.out.println("String: " + s); }
print(5); // the compiler picks print(int)
print("Hello"); // the compiler picks print(String)The compiler can see the argument types in the source code, so it fixes the choice before the program ever runs. Nothing about the choice can change at run time. It is called static binding because it is fixed.
Run-time polymorphism (overriding)
Animal a;
if (userChoice == 1) a = new Dog();
else a = new Cat();
a.sound(); // Woof or Meow: only known while the program runsHere the compiler cannot know which object a will refer to, because it depends on the user's choice. All the compiler checks is that Animal has a sound() method. When the line runs, the JVM looks at the actual object and calls its version. This is dynamic binding.
What is not polymorphic
Only instance methods that can be overridden use dynamic binding. These are always decided at compile time, from the variable's declared type:
staticmethods (they belong to a class, not to an object);privatemethods (they cannot be seen, and so cannot be overridden);finalmethods (they cannot be overridden);- attributes: if a subclass declares an attribute with the same name, the variable's type decides which one you get. This is one more reason to keep attributes private.
Remember
- Overloading: same name, different parameters, chosen by the compiler.
- Overriding: same signature in a subclass, chosen by the JVM from the actual object.
- The declared type decides what you may call; the actual object decides which overridden version runs.