欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長(zhǎng)資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          JVM中的執(zhí)行引擎在執(zhí)行java代碼的時(shí)候,一般有解釋執(zhí)行(通過(guò)解釋器執(zhí)行)和編譯執(zhí)行(通過(guò)即時(shí)編譯器產(chǎn)生本地代碼執(zhí)行)兩種選擇。

          棧幀

          定義:

          棧幀是用于支持虛擬機(jī)進(jìn)行方法調(diào)用和方法執(zhí)行的數(shù)據(jù)結(jié)構(gòu),它位于虛擬機(jī)棧里面。

          作用:

          每個(gè)方法從調(diào)用開(kāi)始到執(zhí)行完成的過(guò)程中,都對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧里面從入棧到出棧的過(guò)程。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          特點(diǎn):

          (1)棧幀包括了局部變量表,操作數(shù)棧等,到底是需要多大的局部變量表,多深的操作數(shù)棧是在編譯期確定的。因?yàn)橐粋€(gè)棧幀需要分配多少內(nèi)存,不會(huì)受到程序運(yùn)行期變量數(shù)據(jù)的影響。

          (2)兩個(gè)棧幀之間的數(shù)據(jù)共享。在概念模型中,兩個(gè)棧幀是完全獨(dú)立的,但是在虛擬機(jī)的實(shí)現(xiàn)里會(huì)做一些優(yōu)化處理,令兩個(gè)棧幀出現(xiàn)一部分重疊。這樣在進(jìn)行方法調(diào)用時(shí),就可以共用一部分?jǐn)?shù)據(jù),無(wú)須進(jìn)行額外的參數(shù)復(fù)制傳遞。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          (1)局部變量表

          局部變量表是一組變量值存儲(chǔ)空間,用于存放方法參數(shù)和方法內(nèi)部定義的局部變量。

          //方法參數(shù)    max(int a,int b)
          int a;//全局變量 void say(){    int b=0;//局部變量  }

          局部變量和類(lèi)變量(用static修飾的變量)不同

          類(lèi)變量有兩次賦初始值的過(guò)程:準(zhǔn)備階段(賦予系統(tǒng)初始值)和初始化階段(賦予程序員定義的初始值)。所以即使在初始化階段沒(méi)有為類(lèi)變量賦值也沒(méi)關(guān)系,它仍然有一個(gè)確定的初始值。
          但局部變量不一樣,如果定義了,但沒(méi)有賦初始值,是不能使用的。

          (2)操作棧

          當(dāng)一個(gè)方法剛剛開(kāi)始執(zhí)行的時(shí)候,這個(gè)方法的操作數(shù)棧是空的,在方法的執(zhí)行過(guò)程中,會(huì)有各種字節(jié)碼指令往操作數(shù)棧中寫(xiě)入和提取內(nèi)容,也就是出棧、入棧操作。

          例如,計(jì)算:

          int a=2+3

          操作數(shù)棧中最接近棧頂?shù)膬蓚€(gè)元素是2和3,當(dāng)執(zhí)行iadd指令時(shí),會(huì)將2和3出棧并相加,然后將相加的結(jié)果5入棧。

          (3)動(dòng)態(tài)鏈接

          Class文件的常量池中存有大量的符號(hào)引用,字節(jié)碼中的方法調(diào)用指令就以常量池中指向方法的符號(hào)引用作為參數(shù)。這些符號(hào)引用分為兩部分:

          靜態(tài)解析:在類(lèi)加載階段或第一次使用的時(shí)候就轉(zhuǎn)化為直接引用。動(dòng)態(tài)鏈接:在每一次運(yùn)行期間轉(zhuǎn)化為直接引用。

          (4)返回地址

          當(dāng)一個(gè)方法開(kāi)始執(zhí)行后,只有兩種方式可以退出這個(gè)方法:正常退出、異常退出。無(wú)論采用何種退出方式,在方法退出之后,都需要返回到方法被調(diào)用的位置,程序才能繼續(xù)執(zhí)行。

          當(dāng)方法正常退出時(shí)

          調(diào)用者的PC計(jì)數(shù)器作為返回地址。棧幀中一般會(huì)保存這個(gè)計(jì)數(shù)器值。

          當(dāng)方法異常退出時(shí)

          返回地址是要通過(guò)異常處理器表來(lái)確定的。棧幀中一般不會(huì)保存這部分信息。

          方法調(diào)用

          方法調(diào)用是確定調(diào)用哪一個(gè)方法。

          (1)解析

          對(duì)“編譯器可知,運(yùn)行期不可變”的方法進(jìn)行調(diào)用稱(chēng)為解析。符合這種要求的方法主要包括

          靜態(tài)方法,用static修飾的方法私有方法,用private修飾的方法

          (2)分派

          分派講解了虛擬機(jī)如何確定正確的目標(biāo)方法。分派分為靜態(tài)分派和動(dòng)態(tài)分派。講解靜動(dòng)態(tài)分派之前,我們先看個(gè)多態(tài)的例子。

          Human man=new Man();

          在這段代碼中,Human為靜態(tài)類(lèi)型,其在編譯期是可知的。Man是實(shí)際類(lèi)型,結(jié)果在運(yùn)行期才可確定,編譯期在編譯程序的時(shí)候并不知道一個(gè)對(duì)象的實(shí)際類(lèi)型是什么。

          靜態(tài)分派:

          所有依賴(lài)靜態(tài)類(lèi)型來(lái)定位方法執(zhí)行版本的分派動(dòng)作稱(chēng)為靜態(tài)分派。它的典型應(yīng)用是重載。

          public class StaticDispatch{      static abstract class Human{       }      static class Man extends Human{     }     static class Woman extends Human{     }     public void say(Human hum){           System.out.println("I am human");       }       public void say(Man hum){           System.out.println("I am man");       }       public void say(Woman hum){           System.out.println("I am woman");       }            public static void main(String[] args){           Human man = new Man();           Human woman = new Woman();           StaticDispatch sr = new StaticDispatch();           sr.say(man);           sr.say(woman);       }   }

          運(yùn)行結(jié)果是:

          I am human I am human

          為什么會(huì)產(chǎn)生這個(gè)結(jié)果呢?
          因?yàn)榫幾g器在重載時(shí),是通過(guò)參數(shù)的靜態(tài)類(lèi)型而不是實(shí)際類(lèi)型作為判斷依據(jù)的。在編譯階段,javac編譯器會(huì)根據(jù)參數(shù)的靜態(tài)類(lèi)型決定使用哪個(gè)重載版本,所以?xún)蓚€(gè)對(duì)say()方法的調(diào)用實(shí)際為sr.say(Human)。

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

          在運(yùn)行期根據(jù)實(shí)際類(lèi)型確定方法執(zhí)行版本的分派過(guò)程。它的典型應(yīng)用是重寫(xiě)。

          public class DynamicDispatch{      static abstract class Human{               protected abstract void say();     }      static class Man extends Human{             @Override              protected abstract void say(){              System.out.println("I am man");               }     }     static class Woman extends Human{          @Override              protected abstract void say(){              System.out.println("I am woman ");               }     }          public static void main(String[] args){           Human man = new Man();           Human woman = new Woman();           man.say();         woman.say();         man=new Woman();         man.say();     }   }

          運(yùn)行結(jié)果:

          I am man I am woman  I am woman

          這似乎才是我們平時(shí)敲的java代碼。對(duì)于方法重寫(xiě),在運(yùn)行時(shí)才確定調(diào)用哪個(gè)方法。由于Human的實(shí)際類(lèi)型是man,因此調(diào)用的是man的name方法。其余的同理。

          動(dòng)態(tài)分派的實(shí)現(xiàn)依賴(lài)于方法區(qū)中的虛方法表,它里面存放著各個(gè)方法的實(shí)際入口地址。如果某個(gè)方法在子類(lèi)中被重寫(xiě)了,那子類(lèi)方法表中的地址將會(huì)替換為指向子類(lèi)實(shí)現(xiàn)版本的入口地址,否則,指向父類(lèi)的實(shí)現(xiàn)入口。

          單分派和多分派:

          方法的接收者與方法的參數(shù)統(tǒng)稱(chēng)為方法的宗量,根據(jù)分派基于多少種宗量,分為單分派和多分派。

          在靜態(tài)分派中,需要調(diào)用者的實(shí)際類(lèi)型和方法參數(shù)的類(lèi)型才能確定方法版本,所以其是多分派類(lèi)型。在動(dòng)態(tài)分派中,已經(jīng)知道了參數(shù)的實(shí)際類(lèi)型,所以此時(shí)只需知道方法調(diào)用者的實(shí)際類(lèi)型就可以確定出方法版本,所以其是單分派類(lèi)型。綜上,java是一門(mén)靜態(tài)多分派,動(dòng)態(tài)單分派的語(yǔ)言。

          字節(jié)碼解釋執(zhí)行引擎

          虛擬機(jī)中的字節(jié)碼解釋執(zhí)行引擎是基于棧的。下面通過(guò)一段代碼來(lái)仔細(xì)看一下其解釋的執(zhí)行過(guò)程。

          public int calc(){       int a = 100;       int b = 200;       int c = 300;       return (a + b) * c;   }

          第一步:將100入棧。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          第二步:將操作棧中的100出棧并存放到局部變量中。后面的200,300同理。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          第三步:將局部變量表中的100復(fù)制到操作數(shù)棧頂。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          第四步:將局部變量表中的200復(fù)制到操作數(shù)棧頂。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          第五步:將100和200出棧,做整型加法,最后將結(jié)果300重新入棧。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          第六步:將第三個(gè)數(shù)300從局部變量表復(fù)制到棧頂。接下來(lái)就是將兩個(gè)300出棧,進(jìn)行整型乘法,將最后的結(jié)果90000入棧。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          第七步:方法結(jié)束,將操作數(shù)棧頂?shù)恼椭捣祷亟o此方法的調(diào)用者。

          JAVA虛擬機(jī)(JVM)詳細(xì)介紹(六)——字節(jié)碼執(zhí)行引擎

          以上便是關(guān)于JAVA虛擬機(jī)——字節(jié)碼執(zhí)行引擎的全部介紹,

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)