<font id="tbtdb"></font>

        <sub id="tbtdb"><delect id="tbtdb"></delect></sub>

          <progress id="tbtdb"></progress>
          <address id="tbtdb"></address><thead id="tbtdb"></thead>
          <font id="tbtdb"></font>

          <meter id="tbtdb"><cite id="tbtdb"><dl id="tbtdb"></dl></cite></meter>

          好程序員-千鋒教育旗下高端IT職業教育品牌

          400-811-9990
          我的賬戶
          好程序員

          專注高端IT職業培訓

          親愛的猿猿,歡迎!

          已有賬號,請

          如尚未注冊?

          [JavaEE] 好程序員Java學習路線分享JVM類加載機制

          [復制鏈接]
          219 0
          葉子老師 發表于 2019-9-18 17:20:26 | 只看該作者 |閱讀模式 打印 上一主題 下一主題
          好程序員Java培訓學習路線分享JVM類加載機制JVM相關概念
          - jdk<br>
              jdkJava Development KitJava開發包,是Java開發人員用于編譯和調試程序的一套程序的集合。
          - jre<br>
              jreJava Runtime EvironmentJava運行時環境,是運行Java程序的平臺,所有的Java程序必須在這個平臺中才能執行。
          - jvm<br>
          jvmJava Virtual MachineJava虛擬機,是用代碼虛擬出來的計算機,模擬執行計算機的各項功能,它有自己的硬件架構,如:處理器、堆棧、寄存器等,還有自己的一套指令系統,在不同的操作系統上都可以安裝JVM,從而實現Java程序在不同的操作系統上都能執行,JVM就是為實現Java的跨平臺特性。
          JVM加載類的過程
          我們執行Java程序開發出來后,需要先編譯再執行,JVM就負責加載類的過程。<br>
          類加載的過程分為:
          1. 加載
          2. 驗證
          3. 準備
          4. 解析
          5. 初始化
          類加載的具體過程
          下面詳細介紹下這幾個過程:
          1. 加載<br>
              在加載類的過程要完成:
              1. 根據類的全名限定符,獲取class二進制流,這個流可以從磁盤上的classjar文件獲得,也可以從網絡中獲得。
              2. 將類的靜態存儲結構轉化為方法區的運行時動態存儲結構
              3. 在內存的堆中生成對應的java.lang.Class對象,作為方法區的入口
          2. 驗證<br>
              加載類完成后,就進入了驗證過程,這個過程保證了前面生成的Class對象中的信息,不會危害JVM的安全。<br>
              需要驗證的方面有:
              1. 文件格式驗證,是要驗證字節流是否符合Class文件格式的規范,并且能被當前版本的虛擬機處理。如驗證魔數是否0xCAFEBABE;主、次版本號是否正在當前虛擬機處理范圍之內;常量池的常量中是否有不被支持的常量類型等等,該驗證階段的主要目的是保證輸入的字節流能正確地解析并存儲于方法區中,經過這個階段的驗證后,字節流才會進入內存的方法區中存儲,所以后面的三個驗證階段都是基于方法區的存儲結構進行的。
              2. 元數據驗證,是對字節碼描述的信息進行語義分析,以保證其描述的信息符合Java語言規范的要求。可能包括的驗證如:這個類是否有父類;這個類的父類是否繼承了不允許被繼承的類;如果這個類不是抽象類,是否實現了其父類或接口中要求實現的所有方法。
              3. 字節碼驗證,主要工作是進行數據流和控制流分析,保證被校驗類的方法在運行時不會做出危害虛擬機安全的行為。如果一個類方法體的字節碼沒有通過字節碼驗證,那肯定是有問題的;但如果一個方法體通過了字節碼驗證,也不能說明其一定就是安全的。
              4. 符號引用驗證,發生在虛擬機將符號引用轉化為直接引用的時候,這個轉化動作將在“解析階段”中發生。驗證符號引用中通過字符串描述的權限定名是否能找到對應的類;在指定類中是否存在符合方法字段的描述符及簡單名稱所描述的方法和字段;符號引用中的類、字段和方法的訪問性(privateprotectedpublicdefault)是否可被當前類訪問。
          3. 準備<br>
              準備階段會在方法區中為類的靜態變量分配內存,并賦給默認值。
              ```
              public static int count = 100;
              ```
              如:上面的count變量在準備階段會賦值為0,在初始化時再賦值為100;
          4. 解析<br>
              解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程。
              - 符號引用(Symbolic Reference<br>
                  符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義地定位到目標即可。符號引用與虛擬機實現的內存布局無關,引用的目標并不一定已經加載到內存中。
              - 直接引用(Direct Reference<br>
                  直接引用可以是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。直接引用是與虛擬機實現的內存布局相關的,如果有了直接引用,那么引用的目標必定已經在內存中存在。
          5. 初始化<br>
              類初始化是類加載過程的最后一步,前面的類加載過程,除了在加載階段用戶應用程序可以通過自定義類加載器參與之外,其余動作完全由虛擬機主導和控制。到了初始化階段,才真正開始執行類中定義的Java程序代碼。<br>
              初始化階段是執行類構造器<clinit>()方法的過程。<clinit>()方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊(static{})中的語句合并產生的。
              那么何時執行初始化呢?
              1. 創建類的實例
              2. 訪問類的靜態變量(除常量外,final修飾的)
                  原因:常量一種特殊的變量,因為編譯器把他們當作值而不是屬性來對待。
              3. 訪問類的靜態方法
              4. 反射如(Class.forName("com.test.Person"))
              5. 當初始化一個類時,發現其父類還未初始化,則先調用父類的初始化
              6. 虛擬機啟動時,定義了main()方法的那個類先初始化
          代碼案例
          了解了類的加載機制,我們來看一道面試題:
          ```
          public class MySingleton {
                  private static MySingleton singleton = new MySingleton();
                  public static int count1 = 0;
                  public static int count2;
                 
                  private MySingleton(){
                          count1++;
                          count2++;
                  }
                 
                  public static MySingleton getInstance(){
                          return singleton;
                  }
                 
                  public static void main(String[] args) {
                          MySingleton singleton = MySingleton.getInstance();
                          System.out.println("count1-->"+MySingleton.count1);
                          System.out.println("count2-->"+MySingleton.count2);
                  }
          }
          上面的結果,大多數同學可能認為兩個靜態變量都是1,結果比較意外:
          ```
          count1-->0
          count2-->1
          ```
          這是為什么呢?下面我們來分析下:
          1. 首先我們知道在類的準備階段會為靜態變量賦默認值:<br>
          singleton = null;
          count1 = 0;
          count2 = 0;
          2. 當調用類的靜態方法getInstance后,引發類的初始化,先執行new MySingleton() 調用構造方法,這時:<br>
          count1 = 1;
          count2 = 1;
          3. 繼續初始化,為變量賦值,count1賦值為0count2沒有賦值就保留值1,結果就是:<br>
          count1 = 0;
          count2 = 1;
          總結
          JVM是代碼模擬的計算機,有自己的硬件和軟件,JVM能實現Java類的加載和運行,具體加載過程有:加載、驗證、準備、解析、初始化5個步驟組成。
          好程序員Java培訓官網:http://www.xn122.com/

          精彩內容,一鍵分享給更多人!
          收藏
          收藏0
          轉播
          轉播
          分享
          淘帖0
          支持
          支持0
          反對
          反對0
          回復

          使用道具 舉報

          您需要登錄后才可以回帖

          本版積分規則

          關注我們
          好程序員
          千鋒好程序員

          北京校區(總部):北京市海淀區寶盛北里西區28號中關村智誠科創大廈

          深圳西部硅谷校區:深圳市寶安區寶安大道5010號深圳西部硅谷B座A區605-619

          杭州龍馳智慧谷校區:浙江省杭州市下沙經濟技術開發區元成路199號龍馳智慧谷B座7層

          鄭州校區:鄭州市二七區航海中路60號海為科技園C區10層、12層

          Copyright 2007-2019 北京千鋒互聯科技有限公司 .All Right

          京ICP備12003911號-5 京公安網11010802011455號

          請您保持通訊暢通1對1咨詢馬上開啟

          电影韩国三级2019在线观看