通過分派的講解可以知道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)
重寫,就從下往上找