<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      深入理解JVM(③)虛擬機(jī)的類加載時(shí)機(jī)

      前言

      Java虛擬機(jī)把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直接使用的Java類型,這個(gè)過(guò)程被稱為虛擬機(jī)的類加載機(jī)制。

      類加載的時(shí)機(jī)

      一個(gè)類型從被加載到虛擬機(jī)內(nèi)存中開(kāi)始,到卸載除內(nèi)存為止,它的生命周期將會(huì)經(jīng)歷加載(Loading)、驗(yàn)證(Verification)、準(zhǔn)備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和 卸載(Unloading)、七個(gè)階段,其中驗(yàn)證、準(zhǔn)備、解析三個(gè)部分統(tǒng)稱為連接(Linking)
      類的生命周期如下圖:
      類的生命周期
      其實(shí)加載、驗(yàn)證、準(zhǔn)備、初始化和卸載這五個(gè)階段的順序是確定的,類型的加載過(guò)程必須按照這種順序按部就班地開(kāi)始,而解析階段則不一定:它在某些情況下可以在初始化階段之后再開(kāi)始,這是為了支持Java語(yǔ)音的運(yùn)行時(shí)綁定特性(也稱為動(dòng)態(tài)綁定或晚期綁定)。
      在什么情況下需要開(kāi)始類加載過(guò)程的第一個(gè)階段“加載”,《Java虛擬機(jī)規(guī)則》中并沒(méi)有進(jìn)行強(qiáng)制約束,但是對(duì)于初始化階段《Java虛擬機(jī)規(guī)范》則是嚴(yán)格規(guī)定了有且只有以下六種情況必須立即對(duì)類進(jìn)行“初始化”。

      1. 遇到new、getstatic、putstaticinvokestatic這四條字節(jié)碼指令時(shí),如果類型沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其初始化階段。
        涉及到這四條指令的典型場(chǎng)景有:
      • 使用new關(guān)鍵字實(shí)例化對(duì)的時(shí)候。
      • 讀取或設(shè)置一個(gè)類型的靜態(tài)字段(被final修飾、已在編譯期把結(jié)果放入常量池的靜態(tài)字段除外)的時(shí)候。
      • 調(diào)用一個(gè)類型的靜態(tài)方法的時(shí)候。
      1. 使用 java.lang.reflect 包的方法對(duì)類型進(jìn)行反射調(diào)用的時(shí)候,如果類型沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其初始化。
      2. 當(dāng)初始化類型的時(shí)候,如果發(fā)現(xiàn)其父類還沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其父類的初始化。
      3. 當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要指定一個(gè)要執(zhí)行的主類(包含main()方法的那個(gè)類),虛擬機(jī)會(huì)先初始化這個(gè)主類。
      4. 當(dāng)使用JDK7新加入的動(dòng)態(tài)語(yǔ)言支持時(shí),如果一個(gè)java.lang.invoke.MethodHandle實(shí)例最后的解析結(jié)果為REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四種類型的方法句柄,并且這個(gè)方法句柄對(duì)應(yīng)的類沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其初始化。
      5. 當(dāng)一個(gè)接口中定義了JDK8新加入的默認(rèn)方法(被default關(guān)鍵字修飾的接口方法)時(shí),如果這個(gè)接口的實(shí)現(xiàn)類發(fā)生了初始化,那該接口要在其之前被初始化。
        除了以上的這個(gè)六種場(chǎng)景外,所有引用類型的方式都不會(huì)觸發(fā)初始化,稱為被動(dòng)引用。
        下面來(lái)看一下哪些是被動(dòng)引用:

      例子??1:

      父類

      package com.jimoer.classloading;
      
      /**
       * @author jimoer
       * @date Create in 2020/06/24 16:08
       * @description 通過(guò)子類引用父類的靜態(tài)字段,不會(huì)導(dǎo)致子類初始化。
       */
      public class FatherClass {
      
          static {
              System.out.println("FatherClass init!!!!!");
          }
      
          public static int value = 666;
      
      }
      

      子類

      package com.jimoer.classloading;
      
      public class SonClass extends FatherClass{
      
          static {
              System.out.println("SonClass init!!!");
          }
      
      }
      

      測(cè)試類

      @Test
      public void testInitClass(){
          System.out.println(SonClass.value);
      }
      

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

      FatherClass init!!!!!
      666
      

      通過(guò)運(yùn)行結(jié)果我們看到,只輸出了“FatherClass init!!!!!”,并沒(méi)有輸出“SubClass init!!!”,這是因?yàn)閷?duì)于使用靜態(tài)字段,只有直接定義這個(gè)字段的類才會(huì)被初始化,因此通過(guò)子類來(lái)引用父類中定義的靜態(tài)字段,并不會(huì)初始化子類。

      例子??2:

      /**
       * 通過(guò)數(shù)組定義來(lái)引用類,不會(huì)觸發(fā)此類的初始化
       */
      @Test
      public void testInitClass2(){
          FatherClass[] fathers = new FatherClass[5];
      }
      

      運(yùn)行結(jié)果:未打印任何信息。
      通過(guò)運(yùn)行結(jié)果我們發(fā)現(xiàn),并沒(méi)有打印出 FatherClass init!!!!! ,這說(shuō)明并沒(méi)有觸發(fā)Father類的初始化階段。但是這段代碼里面觸發(fā)了另一個(gè)名為“[Lcom.jimoer.classloading.FatherClass”的類的初始化階段,它是一個(gè)由虛擬機(jī)自動(dòng)生成的、直接繼承與java.lang.Object的子類,創(chuàng)建動(dòng)作由字節(jié)碼newarray觸發(fā)。這個(gè)類代表了一個(gè)元素類型為FatherClass的一維數(shù)組,數(shù)組中應(yīng)用的屬性和方法(length屬性和clone()方法)都實(shí)現(xiàn)在這個(gè)類里。

      例子??3:

      /**
       * @author jimoer
       * 常量在編譯階段會(huì)存入調(diào)用類的常量池中,
       * 本質(zhì)上沒(méi)有直接引用到定義常量的類,
       * 因此不會(huì)觸發(fā)定義常量的類的初始化。
       */
      public class ConstantClass {
          
          static {
              System.out.println("ConstantClass init !!!");
          }
          
          public static final String CLASS_LOAD = "class load test !!!";
          
      }
      

      使用

      /**
       * 使用常量
       */
      @Test
      public void testInitClass3(){
          System.out.println(ConstantClass.CLASS_LOAD);
      }
      

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

      class load test !!!
      

      通過(guò)運(yùn)行結(jié)果,我們看到當(dāng)在使用一個(gè)類的常量時(shí),并不會(huì)初始化定義了常量的類。這是因?yàn)殡m然在Java源碼中確實(shí)引用了ConstatClass的類的常量CLASS_LOAD,但其實(shí)在編譯階段通過(guò)常量傳播優(yōu)化,已經(jīng)將此常量的值“class load test !!!”直接存儲(chǔ)在使用常量的類中的常量池中了,所以在使用ConstantClass.CLASS_LOAD時(shí)候,實(shí)際上都被轉(zhuǎn)化為在使用類自身的常量池的引用了。

      接口也是有初始化過(guò)程的,上面的代碼都是用靜態(tài)語(yǔ)句塊“static {}”來(lái)輸出初始化信息的,而接口中不能使用static{}語(yǔ)句塊,但編譯器仍然會(huì)為接口生成“()”類構(gòu)造器,用于初始化接口中所定義的成員變量。
      還有一點(diǎn)接口與類不同,當(dāng)一個(gè)類在初始化時(shí),要求其父類全部都已經(jīng)初始化過(guò)了,但是在一個(gè)接口初始化時(shí),并不要求其父接口全部都完成了初始化,只有在真正使用到父接口的時(shí)候(例如引用接口中的常量)才會(huì)初始化。

      posted @ 2020-06-24 18:11  紀(jì)莫  閱讀(563)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 中文字幕亚洲综合久久| 亚洲一区二区中文字幕| 无码伊人久久大杳蕉中文无码| av在线播放国产一区| 久久精品人人看人人爽| 欧美一本大道香蕉综合视频| 国产乱色国产精品免费视频 | 国产精品男女午夜福利片| 2021国产精品视频网站| 亚洲中文字幕在线观看| 老熟妇乱子交视频一区| 亚洲综合av男人的天堂| 亚洲精品第一区二区三区| 日韩高清国产中文字幕| 国产一区二区三区十八禁| 九九视频热最新在线视频| 97se亚洲综合自在线| 国产精品视频午夜福利| 久色伊人激情文学你懂的| 国产精品系列在线免费看| 日本边添边摸边做边爱| 亚洲国产日韩a在线播放| 国产精品国产片在线观看| 午夜一区欧美二区高清三区| 中文字幕国产精品av| 国内精品免费久久久久电影院97| 一个人看的www免费高清视频| 永泰县| 国产最新精品系列第三页| 最新亚洲人成网站在线影院| 精品无码人妻一区二区三区| 国产精品成人午夜久久| 亚洲精品一区二区动漫| 亚洲欧美国产精品专区久久| 深夜福利啪啪片| 东京热一区二区三区在线| 日本极品少妇videossexhd| 波多野结衣久久一区二区| 一区二区三区自拍偷拍视频| 精品视频福利| 视频一区视频二区视频三|