Java虛擬機如何加載類的?

引言

上一篇文章談到Java運行的流程,其中有一環是類加載。今天就繼續深刻探討JVM如何加載虛擬機。
首先JVM加載類的通常流程分三步:
·加載
·連接
·初始化
那麼是否所有Java類都是這樣三步走的方式加載呢?咱們能夠從Java的數據類型去出發。Java分基本類型和引用類型。其中按照面向對象的特性,一切皆對象,那麼對於基本類型也應該是對象。可是爲了在執行效率和內存佔用上進行調優,Java將基本類型特殊處理。因此Java基本類型加載都是Java虛擬機預先定義好了,因此沒有加載這個步驟了。引用類型就是類,接口,數組。其中數組是直接由虛擬機直接生成的。類和接口是字節流,都是須要加載。java

正文

Java基本類型

首先先看下基本類型的默認值和值域。
圖片描述數組

總結
1.無符號類型:boolean和char
2.boolean在Java虛擬機中,根據虛擬機規範轉換爲int類型,false爲0,true爲1數據結構

引用類型

引用類型中的數組是直接由Java虛擬機直接生成,接下來直接講類和接口。爲了敘述方便直接統稱爲類。類的加載分三步。spa

加載

加載是經過加載器進行加載的。Java虛擬機有個一加載機制,叫作雙親委派模型。具體就是當一個類加載器拿到這個類的時候先給本身的父類加載器進行加載,若是父類加載器沒有找到所請求的類,纔會給該類加載器。仍是挺尊老愛幼的。那麼加載器有不少中,在Java9以前分三類。Java9以後分兩類。對象

分類:
Java9以前
·啓動類加載器:負責加載最爲基礎和最爲重要的類。好比存放在jre的lib目錄的jar包中的類以及虛擬機參數-Xbootclasspath指定的類。
·擴展類加載器:擴展類加載器的父類的加載器是啓動類加載器。擴展類加載器加載相對次要可是又通用的類。好比jre中lib/ext目錄下的jar包中的類以及由系統變量java.ext.dir指定的類。
·應用類加載器:應用類加載器的父類加載器是擴展類加載器。負責加載應用加載應用程序路徑的類(這裏的應用程序的路徑就是虛擬機參數-cp/-classpath,系統變量java.class.path或環境變量CLASSPATH指定的路徑)。接口

Java9以後
啓動類加載器:同上
平臺類加載器:Java9引入模塊系統,因此除了少數的幾個關鍵模塊是用啓動類加載器加載,其他的都有平臺類加載器加載。圖片

類加載器除了提供加載功能,還提供命名空間的功能,這個就很像Java的包名同樣。即時是同一個類,通過不一樣的類加載器,命名不一樣那這兩個類也是否是同一個類。內存

連接

何爲連接,就是講加載的類合併至Java虛擬機,使之可以執行的過程。具體流程能夠分類驗證,準備以及解析三個過程。
驗證:驗證的目的就是須要符合Java虛擬機的規範。
準備:爲加載類的靜態字段分配內存,部分Java虛擬機還會在這階段構造其餘跟類層次相關的數據結構,好比說用來實現虛方法的動態綁定的方法表。
解析:當class文件加載到虛擬機以前這個類不知道本身的成員變量和成員方法的地址,因此編譯器會生成一個符號引用,這個符號應用包括所在類的名字,目標方法的名字,接收參數類型以及返回類型。解析就是將這個符號引用轉化爲實際引用。若是符號引用指向的類沒有加載,那麼會觸發這個類進行加載,可是不會連接和初始化。編譯器

Java虛擬機規範並無要求連接過程完成解析,若是某些字節碼使用了符號引用,那麼在執行這些字節碼以前,須要完成解析。虛擬機

初始化

初始化就是初始化靜態字段,若是靜態字段被final修改,那麼該字段就會被標記爲常量值,其初始化直接由Java虛擬機完成。其餘的初始化靜態字段的代碼Java編譯器會放在一個方法中而且命名爲<clinit>.初始化就是爲常量值直接賦值和執行<clinit>方法的過程。Java虛擬機會經過加鎖的方式確保<clinit>方法只執行一次。那麼何時會觸發初始化:1.當虛擬機啓動,初始化用戶指定的類。2.當遇到用以新建目標類實例的new指令時,初始化new指令的目標類。3.當遇到調用靜態方法的指令時,初始化該靜態方法所在的類。4.但遇到訪問靜態字段的指令時,初始化該靜態字段所在的類。5.子類的初始化會觸發父類的初始化。6.若是接口定義了default方法,那麼直接實現或者間接實現該接口的類的初始化,會觸發該接口的初始化。7.使用反射API對某個類進行反射調用時,會初始化該類。8.當初次調用MethodHandle實例時,初始化該MethodHandle指向的方法所在的類。

相關文章
相關標籤/搜索