对于重载的方法进行函数调用时,最终选择哪个方法执行是根据方法参数的静态类型决定,而不是其动态类型。
public class ReloadTest {
public static class Human {
}
public static class Man extends Human {
}
public static class Woman extends Human {
}
public void reload(Man man) {
System.out.println("man");
}
public void reload(Human human) {
System.out.println("human");
}
public void reload(Woman woman) {
System.out.println("woman");
}
}
public static void main(String[] args) throws InterruptedException {
ReloadTest reload = new ReloadTest();
Human man = new Man();
Human woman = new Human();
reload.reload(man);
reload.reload(woman);
}
human
human
最终程序的输出结果是两个human,说明编译器是根据参数的静态类型而不是动态类型作为判断选择哪个重载函数的依据。
以Human man = new Man()为例,Human为静态类型,而Man为动态类型。
编译器在重载时是通过参数的实际静态类型而不是其实际类型作为判断依据。并且静态类型在编译期可知(为什么在编译期可知涉及到编译时栈帧的知识),因此,在编译阶段,javac 编译器会根据参数的静态类型决定使用哪个重载版本,并且把这个方法的符号引用写到main()方法里的两条invokevirtual指令的参数中。
所有依赖静态类型来定位方法执行版本的分派动作称为静态分派。静态分派的典型应用就是方法重载。静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的。另外,编译器虽然能够确认出重载版本,但是这个重载版本并不是唯一的,往往其只能确定一个更加合适的版本。产生这种情况的原因是:字面量不需要定义,所以字面量并没有显示的静态类型,它的静态类型只能通过语言上的规则去理解和推断。
(摘自:深入理解Java虚拟机)
网友评论