亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JVM 方法調(diào)用之動(dòng)態(tài)分派(詳解)

 更新時(shí)間:2017年05月01日 09:15:42   投稿:jingxian  
下面小編就為大家?guī)硪黄狫VM 方法調(diào)用之動(dòng)態(tài)分派(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

1. 動(dòng)態(tài)分派

一個(gè)體現(xiàn)是重寫(override)。下面的代碼,運(yùn)行結(jié)果很明顯。

public class App {
 
 public static void main(String[] args) {
  Super object = new Sub();
  object.f();
 }
}

 class Super {
 public void f() {
  System.out.println("super : f()");
 }
 
 public void f(int i) {
  System.out.println("super : f(int)");
 }
}

class Sub extends Super{
 
 @Override
 public void f() {
  System.out.println("sub : f()");
 }
 
 @Override
 public void f(int i) {
  System.out.println("sub : f(int)");
 }
 
 public void f(char c) {
  System.out.println("sub : f(char)");
 }
}

最終輸出sub : f();

那么虛擬機(jī)是怎么做到動(dòng)態(tài)分派的呢?

不同的虛擬機(jī)有不同的實(shí)現(xiàn),最常用的是使用虛方法表(Virtual Method Table)

2. 虛方法表

對(duì)于Super和Sub類,虛方法表大致如下:(靈魂畫師)

上面的靈魂畫作是什么意思呢?

虛方法表中存放著各個(gè)方法的實(shí)際入口地址。如果某個(gè)方法在子類中沒有被重寫,那子類的虛方法表里面的地址入口和父類相同簽名的方法的地址入口是一致的,都指向父類的實(shí)現(xiàn)入口。如果子類中重寫了這個(gè)方法,子類方法表中的地址將會(huì)替換為向子類實(shí)現(xiàn)版本的入口地址。

從上圖主要得出幾個(gè)信息:

a. 上圖的大部分方法,子類Super和Sub均沒有重寫,那么都指向父類Object的類型數(shù)據(jù)。f()和f(int)方法,父類子類都實(shí)現(xiàn)了,那么兩者就指向不同的實(shí)現(xiàn)地址。f(char)只在子類定義實(shí)現(xiàn),自然指向子類的類型數(shù)據(jù)。

b. 為了程序?qū)崿F(xiàn)上的方便,具有相同簽名的方法,在父類,子類的虛方法表中都應(yīng)當(dāng)具有一樣的索引序號(hào),這樣當(dāng)類型變換時(shí),僅需要變更查找的方法表,就可以從不同的虛方法表中按索引轉(zhuǎn)換出所需要的入口地址。

3. 實(shí)例分析

以本文開頭的代碼進(jìn)行分析。通過javap命令查看main方法的指令。

其中的invokevirtual指令詳細(xì)調(diào)用過程是這樣的:

1)指令中的#19指的是App類的常量池中第19個(gè)常量表的索引項(xiàng)。這個(gè)常量表(CONSTATN_Methodref_info)記錄的是方法f()信息的符號(hào)引用,JVM首先根據(jù)這個(gè)符號(hào)引用找到調(diào)用方法f()的類的全限定名com.khlin.Super,這是因?yàn)樽兞縪bject被聲明為Super類型。

2) 在Super類型的方法表中查找方法f(),如果找到,則將方法f()在方法表中的索引項(xiàng)(具體值我不了解,這里將其記為index) 記錄到App類的常量池中第19個(gè)常量表中(常量池解析)。因此,如果Super類型方法表中沒有f(),那么即使Sub類型的方法表有該方法,也會(huì)報(bào)編譯失敗。

3)在調(diào)用invokevirtual指令前有一個(gè)aload_1指令,它會(huì)將開始創(chuàng)建中堆中的Sub對(duì)象的引用壓入操作數(shù)棧。然后invokevirtual指令會(huì)根據(jù)這個(gè)Sub對(duì)象的引用首先找到堆中的Sub對(duì)象,然后進(jìn)一步找到Sub對(duì)象所屬類型的方法表。

4)這時(shí),通過2)查找的index,可以定位到Sub類型方法表中的f()方法,然后通過直接地址找到該方法字節(jié)碼所在的內(nèi)存空間。這就是父類和子類相同簽名的方法索引序號(hào)一致的用處。

4. 綜合考慮:一個(gè)可能想錯(cuò)的例子

將本文開頭的代碼里的main方法稍作修改,調(diào)用其他的方法。

public static void main(String[] args) {
   Super object = new Sub();
   char c = 'a';
   object.f(c);
  }

結(jié)果將輸出sub : f(int)

明明Sub方法里有完全一樣類型的f(char)方法,卻調(diào)用的是f(int).

相信通過前面的學(xué)習(xí),已經(jīng)可以明白原因了。

在object.f(c)調(diào)用時(shí),虛擬機(jī)先到Super類的方法表里,查找最為合適的方法。

Super類里沒有剛好參數(shù)為char的f(char)方法,按照前面靜態(tài)分派和參數(shù)類型自動(dòng)轉(zhuǎn)換的學(xué)習(xí),可以知道,編譯器使用了除了f(char)之外最為合適的方法f(int)。獲取到索引后,通過索引到實(shí)際對(duì)象的Sub方法表里找到f(int)方法,最終執(zhí)行的就是Sub類的f(int)方法。

該方法的字節(jié)碼指令證明了上述的論證。

以上這篇JVM 方法調(diào)用之動(dòng)態(tài)分派(詳解)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • JAVA設(shè)計(jì)模式之備忘錄模式原理與用法詳解

    JAVA設(shè)計(jì)模式之備忘錄模式原理與用法詳解

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之備忘錄模式,簡(jiǎn)單說明了備忘錄模式的概念、原理并結(jié)合實(shí)例形式分析了java備忘錄模式的具體定義及使用方法,需要的朋友可以參考下
    2017-08-08
  • Java在Map轉(zhuǎn)Json字符串時(shí)出現(xiàn)"\"轉(zhuǎn)義字符的解決辦法

    Java在Map轉(zhuǎn)Json字符串時(shí)出現(xiàn)"\"轉(zhuǎn)義字符的解決辦法

    當(dāng)一個(gè)Map被轉(zhuǎn)成Json字符串后,被添加到另一個(gè)Map中,會(huì)出現(xiàn)被加上“\”轉(zhuǎn)義字符的情況,這個(gè)時(shí)候該如何解決呢,下面就來和小編一起了解一下
    2023-07-07
  • spring中的ObjectPostProcessor詳解

    spring中的ObjectPostProcessor詳解

    這篇文章主要介紹了spring中的ObjectPostProcessor詳解,Spring Security 的 Java 配置不會(huì)公開其配置的每個(gè)對(duì)象的每個(gè)屬性,這簡(jiǎn)化了大多數(shù)用戶的配置,畢竟,如果每個(gè)屬性都公開,用戶可以使用標(biāo)準(zhǔn) bean 配置,需要的朋友可以參考下
    2024-01-01
  • 詳細(xì)講解Java抽象類示例

    詳細(xì)講解Java抽象類示例

    這篇文章主要介紹了 Java抽象類示例,抽象類通常用于定義一些公共的方法和屬性,但是這些方法沒有具體的實(shí)現(xiàn),需要的朋友可以參考下
    2023-05-05
  • Java 對(duì)10個(gè)數(shù)進(jìn)行排序的實(shí)現(xiàn)代碼

    Java 對(duì)10個(gè)數(shù)進(jìn)行排序的實(shí)現(xiàn)代碼

    可以利用選擇法,即從后9個(gè)比較過程中,選擇一個(gè)最小的與第一個(gè)元素交換, 下次類推,即用第二個(gè)元素與后8個(gè)進(jìn)行比較,并進(jìn)行交換
    2017-02-02
  • SpringBoot定時(shí)任務(wù)詳解與案例代碼

    SpringBoot定時(shí)任務(wù)詳解與案例代碼

    SpringBoot是一個(gè)流行的Java開發(fā)框架,它提供了許多便捷的特性來簡(jiǎn)化開發(fā)過程,其中之一就是定時(shí)任務(wù)的支持,讓開發(fā)人員可以輕松地在應(yīng)用程序中執(zhí)行定時(shí)任務(wù),本文將詳細(xì)介紹如何在Spring?Boot中使用定時(shí)任務(wù),并提供相關(guān)的代碼示例
    2023-06-06
  • SpringBoot如何指定某些類優(yōu)先啟動(dòng)

    SpringBoot如何指定某些類優(yōu)先啟動(dòng)

    這篇文章主要介紹了SpringBoot如何指定某些類優(yōu)先啟動(dòng),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • java8如何用Stream查L(zhǎng)ist對(duì)象某屬性是否有重復(fù)

    java8如何用Stream查L(zhǎng)ist對(duì)象某屬性是否有重復(fù)

    這篇文章主要介紹了java8如何用Stream查L(zhǎng)ist對(duì)象某屬性是否有重復(fù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java實(shí)現(xiàn)微信支付功能

    java實(shí)現(xiàn)微信支付功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信支付功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • mybatis typeAliases 給實(shí)體類起別名的方法

    mybatis typeAliases 給實(shí)體類起別名的方法

    這篇文章主要介紹了mybatis typeAliases 給實(shí)體類起別名,本文給大家分享兩種用法,通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09

最新評(píng)論