Whether the compiler is actually able to optimize any or all of the three method invocations and resolve the calls at compile time now or in some future implementation is irrelevant: All three method invocations are examples of runtime polymorphism, also known as dynamic dispatch This is contrasted with what is referred to as static polymorphism, also known as method overloading, which is a class having multiple methods with the same name but with different argument types.
Here is a small Java program:
public class Test {
public void foo(String inputString)
{
System.out.println(inputString);
}
public static void main(String[] args) {
Test test = new Test();
test.foo("a"); # very obvious method invocation
}
}
It is very clear to a human what method would be invoked at runtime. Here is the disassembled bytecode:
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void foo(java.lang.String);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_1
4: invokevirtual #3 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
7: return
public static void main(java.lang.String[]);
Code:
0: new #4 // class Test
3: dup
4: invokespecial #5 // Method "<init>":()V
7: astore_1
8: aload_1
9: ldc #6 // String a
11: invokevirtual #7 // Method foo:(Ljava/lang/String;)V
14: return
}
Instruction 11 is a runtime dispatch of a virtual method.
But as I said, even if in some future compiler implementation this was optimized to a different call, that would just be an implementation detail.