通过分派的讲解可以知道java中重载和重写在java虚拟机中是如何是实现的。
静态分派
package org.fenixsoft.polymorphic;
/**
* 方法静态分派演示
* @author zzm
*/
public class StaticDispatch {
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();
StaticDispatch sr = new StaticDispatch();
sr.sayHello(man);
sr.sayHello(woman);
}
}
结果
hello,guy!
hello,guy!
先来了解 Human woman = new Woman();中 Human是静态类型,而Woman是实例类型。在编译的过程中,静态类型是可以知道的。但实例类型不知道。故重载的时候是通过参数的静态类型而不是实际类型判断的。
动态分派
package org.fenixsoft.polymorphic;
/**
* 方法动态分派演示
* @author zzm
*/
public class DynamicDispatch {
static abstract class Human {
protected abstract void sayHello();
}
static class Man extends Human {
@Override
protected void sayHello() {
System.out.println("man say hello");
}
}
static class Woman extends Human {
@Override
protected void sayHello() {
System.out.println("woman say hello");
}
}
public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
man.sayHello();
woman.sayHello();
man = new Woman();
man.sayHello();
}
}
结果
man say hello
woman say hello
woman say hello
来看看,这里可以通过静态分派来区分吗?显然不行。sayHello都没有传入参数,怎么来判断实际类型。且如果是重写的话,实际类型也是相同的。故重写只能通过动态分派来进行区分。
如何实现?
类加载后,每个方法都有自己的符号引用。通过invokevirtual指令,把符号应用解析到不同的直接引用上面,这个过程就是方法重写的本质。
如何执行?
1.找到操作数栈顶的第一个元素所指向的对象的实际类型,也就是这个调用方法的对象实际类型。记做c
2.c如果符合常量中的各种描述,且访问权限校验成功,那就返回这个方法的直接引用。
3.否则,按照继承关系,从下往上进行第2步。
4.找不到就抛出异常
静态分派和动态分派混合应用
/**
* 单分派、多分派演示
* @author zzm
*/
public class Dispatch {
static class QQ {}
static class _360 {}
public static class Father {
public void hardChoice(QQ arg) {
System.out.println("father choose qq");
}
public void hardChoice(_360 arg) {
System.out.println("father choose 360");
}
}
public static class Son extends Father {
public void hardChoice(QQ arg) {
System.out.println("son choose qq");
}
public void hardChoice(_360 arg) {
System.out.println("son choose 360");
}
}
public static void main(String[] args) {
Father father = new Father();
Father son = new Son();
father.hardChoice(new _360());
son.hardChoice(new QQ());
}
}
结果
father choose 360
son choose qq
同个类中的方法重载,通过静态分派,只要静态类型是QQ 就调用public void hardChoice(QQ arg)
重写,就从下往上找