```
public class Test{
static abstract class Human{
}
static class Man extends Human{
}
static class Woman extends Human{
}
public void sayHello(Human guy){
System.out.println("hello guy");
}
public void sayHello(Man guy){
System.out.println("hello gentleman");
}
public void sayHello(Woman guy){
System.out.println("hello lady");
}
public static void main(String[] args){
Human man = new Man();
Human woman = new Woman();
Test sr = new Test();
sr.sayHello(man);
sr.sayHello(woman);
}
}
```
`该类的运行结果为
hello guy
hello guy
由此可见虽然调用sayHello方法时入参实际是Human的子类实例,但是在JVM看来man、woman两个入参是
Human的实例。为了验证man、woman的类型可以采用javap这条编译指令:
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object.""
()V
4: return
public void sayHello(Test$Human);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava
io/PrintStream;
3: ldc #22 // String hello guy
5: invokevirtual #24 // Method java/io/PrintStream.print
n:(Ljava/lang/String;)V
8: return
public void sayHello(Test$Man);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava
io/PrintStream;
3: ldc #33 // String hello gentleman
5: invokevirtual #24 // Method java/io/PrintStream.print
n:(Ljava/lang/String;)V
8: return
public void sayHello(Test$Woman);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava
io/PrintStream;
3: ldc #37 // String hello lady
5: invokevirtual #24 // Method java/io/PrintStream.print
n:(Ljava/lang/String;)V
8: return
public static void main(java.lang.String[]);
Code:
0: new #42 // class Test$Man
3: dup
4: invokespecial #44 // Method Test$Man."":()V
7: astore_1
8: new #45 // class Test$Woman
11: dup
12: invokespecial #47 // Method Test$Woman."":()V
15: astore_2
16: new #1 // class Test
19: dup
20: invokespecial #48 // Method "":()V
23: astore_3
24: aload_3
25: aload_1
26: invokevirtual #49 // Method sayHello:(LTest$Human;)V
29: aload_3
30: aload_2
31: invokevirtual #49 // Method sayHello:(LTest$Human;)V
34: return
}
jvm编译时生成的调用方法的符号引用,入参全部标识为Human类。
这是为什么呢?这就需要从JVM 进行讲解了,在代码中定义的Human类成为静态类型,而Man、Woman类则成为实际类型。静态类型在编译期是可知的,但是动态类型只有在运行时才可以确定。解释了这两个概念,结合代码阐述一下,main方法中两次调用sayHello(),在方法接受者已经确定是sr的前提下,调用哪个重载方法,就需要根据入参的类型、数量来进行辨别,但是jvm在重载时是根据静态类型而不是实际类型作为判断依据的。并且静态类型在编译期是可知的,所以选择了sayHello(Human guy)作为重载版本,并把这两个方法的调用写入到了invokevirtual指令的参数中。
下面需要强调动态绑定的发生的前提条件:
需要有继承
父类的引用指向子类对象
必须有重写
但是最关键的触发条件是调用重写的方法。