• <samp id="mz5ne"><acronym id="mz5ne"></acronym></samp>
      <ol id="mz5ne"></ol>
    1. <samp id="mz5ne"></samp>
      <mark id="mz5ne"></mark>

        <fieldset id="mz5ne"></fieldset>

        免费看又黄又无码的网站_久久久高清国产免费观看_亚洲一区二区三区在线免费观看_免费欧洲美女a视频一级毛片_日本最新免费二区三区

        ×

        深入理解Java之java虛擬機干凈利落的規(guī)范總結(jié) 下

        • 作者:新網(wǎng)
        • 來源:新網(wǎng)
        • 瀏覽:100
        • 2018-05-03 17:56:15

        要去正確地實現(xiàn)一臺Java虛擬機,就需要正確地讀取class文件中每一條字節(jié)碼指令并且能正確執(zhí)行這些指令所蘊含的操作即可。

          t0132608ea0fedf6d64.png

        <div>        要去正確地實現(xiàn)一臺Java虛擬機,就需要正確地讀取class文件中每一條字節(jié)碼指令并且能正確執(zhí)行這些指令所蘊含的操作即可。
          由Java虛擬機執(zhí)行的每個方法都會配有零到多個異常處理器。異常處理器描述了其在方法代碼中的有效作用范圍(通過字節(jié)碼偏移量范圍來描述)、能處理的異常類型以及處理異常的代碼所在的位置。要判斷某個異常處理器是否可以處理某個具體的異常,需要同時檢查一場出現(xiàn)的位置是否在異常處理的有效作用范圍內(nèi),以及出現(xiàn)的異常是否是異常處理器聲明可以處理的異常類型或其子類型。當(dāng)拋出異常時,Java虛擬機搜索當(dāng)前方法包含的各個異常處理器,如果能找到可以處理該異常的異常處理器,則將代碼控制權(quán)轉(zhuǎn)向異常處理器中描述的處理異常的分支之中。
          首先簡單介紹一下main方法中各條字節(jié)碼指令所代表的意思:
          0 : 將int類型的常量i壓入操作數(shù)棧中,iconst_0后面跟的那個0代表常量的值為0;
          1:將一個int類型數(shù)據(jù)由保存到本地變量表,istort_1后面的1代表的是指向當(dāng)前棧幀中局部變量表的索引值;
          2:將一個值為3的int類型的常量壓入操作數(shù)棧中。在這里指的是被除數(shù)3;
          3:從局部變量表加載一個int類型值到操作數(shù)棧中,這里指的是除數(shù)i;
          4:對兩個int類型的數(shù)據(jù)做除法;
          5:將兩數(shù)相除之后所得到的int類型數(shù)據(jù)保存到本地變量表;
          6:假如沒有發(fā)生異常的話,那么執(zhí)行完goto到第14條語句,函數(shù)正常返回;
          9:假如發(fā)生了除零異常,就執(zhí)行這條指令,將異常對象保存到局部變量表中;
          10:從局部變量表中加載剛才的那個異常對象到操作數(shù)中;
          11:調(diào)用異常對象的printStackTrace方法
          14:不管是正常完成還是異常完成,最終都會返回。
          在字節(jié)碼下方可以看到一個Exception table。那么它是什么東西呢?其實我們很容易能夠理解它就是異常表,也就是前面我們提過的異常處理器。我們可以明顯地觀察出,其實try-catch代碼塊編譯之后似乎沒有生成任何指令。那么Java語言中的try-catch放到字節(jié)碼當(dāng)中對應(yīng)什么東西呢?其實就是對應(yīng)這個異常處理器。下面我們來解讀一下異常處理器:
          在try語句塊的執(zhí)行過程中如果沒有拋出異常,那么這個異常處理器不會起作用。異常處理器的作用范圍是從字節(jié)碼的第2行到第6行,也就是from-to標(biāo)明的范圍。假如編譯好的代碼里面第2~6句之間有一個類型為java.lang.ArithmeticException的異常實例被拋出,那么操作將轉(zhuǎn)移至第9句繼續(xù)執(zhí)行,即進入catch語句塊的實踐步驟。假如說拋出的異常不是ArithmeticException實例,那么異常處理器就不能處理該異常,這個異常將返回給上一級的調(diào)用者。
          那假如try語句塊包含多個catch語句塊,在編譯好的代碼中會出現(xiàn)什么樣的結(jié)果呢?
          如果給定的try語句塊包含多個catch語句塊,那么在編譯好的代碼中,多個catch語句塊的內(nèi)容將會連續(xù)排列,在異常表中也會有對應(yīng)的連續(xù)排列的成員,它們的排列順序和源碼中catch語句塊的出現(xiàn)順序一致。main方法在執(zhí)行時,如果try語句塊中拋出了一個異常,這個異常將會被多個catch語句塊捕獲。假如第一個catch不能捕獲異常(當(dāng)然這里的第一個catch語句塊肯定是能處理ArithmeticException,我只是舉個例子),那么異常將交由第二個異常處理器來進行處理,這很容易理解。因為我在第二個catch語句塊中選擇的是將捕獲的異常拋出,所以在字節(jié)碼的第26行可以看到有一個athrow指令,在前面的學(xué)習(xí)當(dāng)中我們知道它是拋出異常的意思,其實也就是對應(yīng)著Java代碼中的throw new Exception()。在這里,我還要順便介紹一下Java創(chuàng)建一個對象的代碼在編譯之后會產(chǎn)生怎樣的字節(jié)碼。
          其實,剛才我所說的throw new Exception()對應(yīng)athrow字節(jié)碼指令只說對了一半,它在編譯之后不僅僅只產(chǎn)生athrow這一條字節(jié)碼指令。因為它還對應(yīng)著一個操作,也就是new一個Exception對象。Java語言實例化一個Exception對象將會產(chǎn)生三條字節(jié)碼指令,即上圖中19,22,23三行:
          為什么會有三條指令呢?dup是做什么的?我們下面一起來學(xué)習(xí)一下
          由于討論的是創(chuàng)建對象,所以在代碼throw new Exception()中我們不看throw,只看new Exception()這一部分代碼。
          new Exception()表達式的作用是:
          創(chuàng)建并默認(rèn)初始化一個Exception對象;
          調(diào)用Exceptioon類的signature為()V的構(gòu)造器;
          表達式的值為一個指向這個對象的引用
          對應(yīng)字節(jié)碼,我們可以看到:
          new Exception()對應(yīng)上面的1
          invokespecial Exception.()V對應(yīng)上面的2
          那么3是怎么來的?
          回歸到字節(jié)碼,我們可以看到new字節(jié)碼指令的作用是創(chuàng)建指定類型的對象實例、對其進行默認(rèn)初始化,并將指向該實例的一個引用壓入操作數(shù)棧頂;
          然后因為invokespecial會消耗操作數(shù)棧頂?shù)囊米鳛閭鹘o構(gòu)造器的"this"參數(shù),所以如果我們希望在invokespecial調(diào)用后在操作數(shù)棧頂還維持有一個指向新建對象的引用,就得在invokespecial之前先“復(fù)制”一份引用----這就是dup的來源。
          以上,就是對創(chuàng)建一個對象編譯之后產(chǎn)生的字節(jié)碼的解釋
          編譯finally語句塊
          剛才我們介紹了異常處理在字節(jié)碼層面的細(xì)節(jié),但是我們還需要注意的是----由于finally能夠保證不管發(fā)生任何情況,都能夠執(zhí)行語句塊中的代碼,所以在日常編碼過程中我們在可能發(fā)生異常的地方(或者是不會發(fā)生異常的地方)經(jīng)常使用finally來釋放某些資源。
          下面我們從虛擬機層面來看看如何保證finally語句塊中的代碼一定會執(zhí)行
          可以看到,其實編譯器是通過在每個分支后面增加冗余代碼的形式來保證finally語句塊中的代碼一定會被執(zhí)行。這里和書上講的有點出入,書上在講解這一塊的時候還是用jsr、jsr_w、ret等程序控制轉(zhuǎn)移指令來解釋的,但是javac在很早之前就不再為finally語句生成jsr和ret指令了。
          如果程序在try語句塊中執(zhí)行了return,那么代碼的行為如下:
          如果有返回值,將返回值保存在局部變量表;
          執(zhí)行跟在后面的冗余finally語句塊中的代碼;
          在finally執(zhí)行完之后,將事先保存在局部變量表中的返回值壓入操作數(shù)棧中之后返回。
          如果在try語句中拋出異常,那么代碼的行為如下:
          將異常保存在局部變量表中
          執(zhí)行finally語句塊中的代碼
          在執(zhí)行完finally語句塊中的代碼后,重新拋出這個事先保存好的異常。
          Java虛擬機中的同步(synchronization)使用monitor的進入和退出來實現(xiàn)的。無論顯式同步(有明確的monitorenter和monitorexit指令),還是隱式同步(依賴方法調(diào)用和返回指令實現(xiàn))都是如此。
          在Java語言中,同步用得最多的地方可能是經(jīng)synchronized所修飾的同步方法。同步方法并不是用monitorenter和monitorexit來實現(xiàn)的,而是由方法調(diào)用指令讀取運行時常量池中方法的ACC_SYNCHRONIZED標(biāo)志來隱式實現(xiàn)的。
          monitorenter和monitorexit指令用于編譯同步語句塊
          編譯器必須確保無論方法以何種方式完成(正常結(jié)束或者是異常結(jié)束),方法中調(diào)用過的每條monitorenter指令都必須有對應(yīng)的monitorexit指令得到執(zhí)行。為了確保在方法異常完成時,monitorenter和monitorexit指令依然可以正確配對執(zhí)行,編譯器會自動生成一個異常處理器,這個異常處理器宣稱自己可以處理所有異常,它的代碼用來執(zhí)行monitorexit指令。
          到這里深入理解Java之java虛擬機干凈利落的規(guī)范總結(jié)就結(jié)束了,不足之處還望大家多多包涵!!覺得收獲的話可以點個關(guān)注收藏轉(zhuǎn)發(fā)一波喔,謝謝大佬們支持。
         

        免責(zé)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻自行上傳,本網(wǎng)站不擁有所有權(quán),也不承認(rèn)相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,請發(fā)送郵件至:operations@xinnet.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,本站將立刻刪除涉嫌侵權(quán)內(nèi)容。

        免費咨詢獲取折扣

        Loading
        国产精品视频白浆免费视频_久久久高清国产免费观看_亚洲一区二区三区在线免费观看_免费欧洲美女a视频一级毛片
      1. <samp id="mz5ne"><acronym id="mz5ne"></acronym></samp>
          <ol id="mz5ne"></ol>
        1. <samp id="mz5ne"></samp>
          <mark id="mz5ne"></mark>

            <fieldset id="mz5ne"></fieldset>
            柏乡县| 兴安盟| 广水市| 塔城市| 民勤县| 宜兰县| 水城县| 平利县| 桐梓县| 南和县| 布拖县| 西畴县| 茌平县| 灵丘县| 铅山县| 如东县| 清水河县| 河西区| 洱源县| 突泉县| 大港区| 乌审旗| 定南县| 华容县| 孟州市| 平远县| 乳山市| 佳木斯市| 慈溪市| 镇宁| 巴楚县| 时尚| 诏安县| 正宁县| 敦化市| 民权县| 新干县| 定安县| 阿城市| 滨海县| 远安县|