java虛擬機(七)靜態分派與動態分派

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章