日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 静态分派_Java中的静态分派与动态分派

發(fā)布時間:2025/3/19 java 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 静态分派_Java中的静态分派与动态分派 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文是《深入理解Java虛擬機》8.3.2節(jié)的讀書筆記,理解有誤的地方,歡迎指正

首先是兩個概念:

靜態(tài)類型,即是變量聲明時的類型。

實際類型,變量實例化時采用的類型。

比如我們有這樣一段代碼

class Human {}

public class Man extends Human {

public static void main(String[] args) {

Human man = new Man();

}

}

我們就稱變量 man 的靜態(tài)類型為 Human,實際類型為 Man。

靜態(tài)分派

所有依賴靜態(tài)類型來定位方法執(zhí)行版本的分派動作稱為靜態(tài)分派,其典型應用是方法重載(根據(jù)參數(shù)的靜態(tài)類型來定位目標方法)。

靜態(tài)分派發(fā)生在編譯階段,因此確定靜態(tài)分派的動作實際上不是由虛擬機執(zhí)行的。

動態(tài)分派

在運行期根據(jù)實際類型確定方法執(zhí)行版本。

比如這樣一段代碼,其中man和woman的靜態(tài)類型都是Human,但是實際類型各異:

public class DynamicDispatch {

public static void main(String[] args) {

Human man = new Man();

Human woman = new Woman();

man.sayHello(); // Output : man say hello

woman.sayHello(); // Output : woman say hello

}

private static abstract class Human {

protected abstract void sayHello();

}

private static class Man extends Human {

protected void sayHello() {

System.out.println("man say hello");

}

}

private static class Woman extends Human {

protected void sayHello() {

System.out.println("woman say hello");

}

}

}

編譯過后所得的字節(jié)碼文件如下:

(常量池的部分內(nèi)容)

Constant pool:

#1 = Methodref #8.#23 // java/lang/Object."":()V

#2 = Class #24 // DynamicDispatch$Man

#3 = Methodref #2.#25 // DynamicDispatch$Man."":(LDynamicDispatch$1;)V

#4 = Class #26 // DynamicDispatch$Woman

#5 = Methodref #4.#25 // DynamicDispatch$Woman."":(LDynamicDispatch$1;)V

#6 = Methodref #13.#27 // DynamicDispatch$Human.sayHello:()V

public class DynamicDispatch {

public DynamicDispatch();

Code:

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: return

public static void main(java.lang.String[]);

Code:

0: new #2 // class DynamicDispatch$Man

3: dup

4: aconst_null

5: invokespecial #3 // Method DynamicDispatch$Man."":(LDynamicDispatch$1;)V

8: astore_1

9: new #4 // class DynamicDispatch$Woman

12: dup

13: aconst_null

14: invokespecial #5 // Method DynamicDispatch$Woman."":(LDynamicDispatch$1;)V

17: astore_2

18: aload_1 // 將第二個引用類型本地變量(man)推送至操作數(shù)棧棧頂

19: invokevirtual #6 // Method DynamicDispatch$Human.sayHello:()V,調(diào)用#6代表的實例方法,并且方法的接收者就是操作數(shù)棧頂元素

22: aload_2

23: invokevirtual #6 // Method DynamicDispatch$Human.sayHello:()V

26: return

}

在main函數(shù)中,0~8是創(chuàng)建Man對象并賦到man,9~17是創(chuàng)建woman對象并賦到woman,18就是將man對象壓入操作數(shù)棧棧頂,接下來19調(diào)用Human的sayHello方法,執(zhí)行的字節(jié)碼指令是invokevirtual,其具有多態(tài)查找過程,在運行時的解析過程大致為:

找到操作數(shù)棧頂?shù)牡谝粋€元素所指向的對象的實際類型,記為C。

如果在類型C中找到與常量中的描述符合簡單名稱都相符的方法,則進行訪問權(quán)限校驗,如果通過則返回這個方法的直接引用,查找過程結(jié)束;如果權(quán)限校驗不通過,返回java.lang.IllegalAccessError異常。

否則,按照繼承關(guān)系從下往上一次對C的各個父類進行第2步的搜索和驗證過程。

如果始終沒有找到合適的方法,則拋出 java.lang.AbstractMethodError異常。

這里方法的接收者——即操作數(shù)棧棧頂元素是man對象,最后的結(jié)果就是調(diào)用了Man中的sayHello方法。同樣的,對woman對象的方法調(diào)用也是如此,最后執(zhí)行的是Woman中的sayHello方法。

由于invokevirtual指令執(zhí)行的第一步就是在運行期間確定接收者的實際類型,所以兩次調(diào)用中的invokevirtual指令把常量池中的類方法符號引用解析到了不同的直接引用上,這個過程就是Java方法重寫的本質(zhì)。

總結(jié)

以上是生活随笔為你收集整理的java 静态分派_Java中的静态分派与动态分派的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。