<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          提問!JVM類加載你真的【了解】了嗎?掌握這幾點,不再難!

          共 6334字,需瀏覽 13分鐘

           ·

          2021-10-25 08:25


          二、類加載子系統(tǒng)

          2.1、類加載器與類的加載過程

          2.1.1、類加載器子系統(tǒng)

          ????類加載器子系統(tǒng)負(fù)責(zé)從文件系統(tǒng)或者網(wǎng)絡(luò)中加載Class文件,class文件在文件開頭有特定的文件標(biāo)識,ClassLoader只負(fù)責(zé)class文件的加載,至于它是否可以運行,則由Execution Engine(執(zhí)行引擎)決定。

          ????加載的類信息存放于一塊稱為方法區(qū)的內(nèi)存空間。除了類的信息外,方法區(qū)中還會存放運行時常量池信息,可能還包括字符串字面量和數(shù)字常量(這部分常量信息是Class文件中常量池部分的內(nèi)存映射)。

          2.1.2、類加載器ClasLoader

          ??? class file存在于本地硬盤上,可以理解為設(shè)計師畫在紙上的模板,而最終這個模板在執(zhí)行的時候是要加載到JVM當(dāng)中來根據(jù)這個 文件實例化出n個一模一樣的實例。

          ??? class file加載到JVM中,被稱為DNA元數(shù)據(jù)模板,放在方法區(qū)。

          ??? .class文件->JVM->最終成為元數(shù)據(jù)模板,此過程就要一個運輸工具(類裝載器Class Loader),扮演一個快遞員的角色。

          2.1.3、加載階段

          ????在加載階段,主要經(jīng)過了加載、鏈接(驗證、準(zhǔn)備、解析)、初始化三個步驟。

          2.1.3.1、加載

          ????加載步驟分為三部曲:

          1. 通過一個類的全限定名獲取定義此類的二進(jìn)制字節(jié)流,將硬盤中的class文件加載進(jìn)JVM內(nèi)存。

          2. 將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。(JDK8以前叫永久代,JKD8及以后叫元空間)。

          3. 在內(nèi)存中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口

          ????我們加載class文件的方式主要有以下的七種:

          1. 從本地系統(tǒng)中直接加載

          2. 通過網(wǎng)絡(luò)獲取,典型場景:Web Applet

          3. 從zip壓縮包中讀取,成為日后jar、war格式的基礎(chǔ)

          4. 運行時計算生成,使用最多的是:動態(tài)代理技術(shù)

          5. 由其他文件生成,典型場景:JSP應(yīng)用

          6. 從專有數(shù)據(jù)庫中提取.class文件,比較少見

          7. 從加密文件中獲取,典型的防Class文件被反編譯的保護(hù)措施

          2.1.3.2、鏈接階段

          2.1.3.2.1、驗證(Verify)

          ????驗證的目的在子確保Class文件的字節(jié)流中包含信息符合當(dāng)前虛擬機(jī)要求,保證被加載類的正確性,不會危害虛擬機(jī)自身安全。

          ????他主要包括四種驗證,文件格式驗證,元數(shù)據(jù)驗證,字節(jié)碼驗證,符號引用驗證。

          2.1.3.2.2、準(zhǔn)備(Prepare)

          ????準(zhǔn)備階段是為類變量分配內(nèi)存并且設(shè)置該類變量的默認(rèn)初始值,即零值。這里不包含用final修飾的static,因為final在編譯的時候就會分配了,準(zhǔn)備階段會顯式初始化。

          ????他也不會為實例變量分配初始化,類變量會分配在方法區(qū)中,而實例變量是會隨著對象一起分配到Java堆中。在準(zhǔn)備階段,只有類沒有對象。

          2.1.3.2.3、解析(Resolve)

          ????解析階段是將常量池內(nèi)的符號引用轉(zhuǎn)換為直接引用的過程(用對象的內(nèi)存地址,而不是對象本身)。事實上,解析操作往往會伴隨著JVM在執(zhí)行完初始化之后再執(zhí)行。

          ????符號引用就是一組符號來描述所引用的目標(biāo)。符號引用的字面量形式明確定義在《java虛擬機(jī)規(guī)范》的Class文件格式中。直接引用就是直接指向目標(biāo)的指針、相對偏移量或一個間接定位到目標(biāo)的句柄。

          ????解析動作主要針對類或接口、字段、類方法、接口方法、方法類型等。對應(yīng)常量池中的CONSTANT_Class_info,CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。

          2.1.3.3、初始化階段

          ????初始化階段就是執(zhí)行類構(gòu)造器方法()的過程。此方法不需定義,是javac編譯器自動收集類中的所有類變量的賦值動作和靜態(tài)代碼塊中的語句合并而來。

          ????構(gòu)造器方法中指令按語句在源文件中出現(xiàn)的順序執(zhí)行。()不同于類的構(gòu)造器。(關(guān)聯(lián):構(gòu)造器是虛擬機(jī)視角下的()

          ????若該類具有父類,JVM會保證子類的()執(zhí)行前,父類的()已經(jīng)執(zhí)行完畢,且虛擬機(jī)必須保證一個類的()方法在多線程下被同步加鎖,也就是說一個類不會被初始化兩次。

          2.1.4、類加載的過程

          /**
          *示例代碼
          */

          public class HelloLoader {
          public static void main(String[] args) {
          System.out.println("Hello World!");
          }
          }
          復(fù)制代碼

          2.2、 類加載器分類

          ??? JVM支持兩種類型的類加載器 。分別為:

          1. 引導(dǎo)類加載器(Bootstrap ClassLoader)。

          2. 自定義類加載器(User-Defined ClassLoader)。(拓展類加載器、系統(tǒng)類加載器、自定義類加載器)

          ????從概念上來講,自定義類加載器一般指的是程序中由開發(fā)人員自定義的一類類加載器,但是Java虛擬機(jī)規(guī)范卻沒有這么定義,而是將所有派生于抽象類ClassLoader的類加載器都劃分為自定義類加載器,無論類加載器的類型如何劃分,在程序中我們最常見的類加載器始終只有3個。

          2.2.1、虛擬機(jī)自帶的加載器

          2.2.1.1、啟動類加載器

          ????啟動類加載器也叫引導(dǎo)類加載器(Bootstrap ClassLoader),他是這個類加載使用 C/C++語言實現(xiàn)的,嵌套在 JVM 內(nèi)部,他并不繼承自 java.lang.ClassLoader,沒有父加載器。我們無法通過Java代碼進(jìn)行獲取。

          ????它用來加載 Java 的核心庫(JAVA_HOME/jre/lib/rt.jar、resources.jar 或 sun.boot.class.path 路徑下的內(nèi)容),用于提供 JVM 自身需要的類。他同時還加載擴(kuò)展類和應(yīng)用程序類加載器,并指定為他們的父類加載器。

          ????出于安全考慮,Bootstrap 啟動類加載器只加載包名為 java、javax、sun 等開頭的類。

          2.2.1.2、擴(kuò)展類加載器

          ????擴(kuò)展類加載器(Extension ClassLoader),他是由Java 語言編寫,由 sun.misc.Launcher$ExtClassLoader 實現(xiàn),派生于 ClassLoader 類。

          ????他的父類加載器為啟動類加載器,從 java.ext.dirs 系統(tǒng)屬性所指定的目錄中加載類庫,或從 JDK 的安裝目錄的 jre/1ib/ext 子目錄(擴(kuò)展目錄)下加載類庫。如果用戶創(chuàng)建的 JAR 放在此目錄下,也會自動由擴(kuò)展類加載器加載。

          2.2.1.3、應(yīng)用程序類加載器

          ????應(yīng)用程序類加載器也叫做系統(tǒng)類加載器(AppClassLoader),他是由java語言編寫,由sun.misc.LaunchersAppClassLoader實現(xiàn),派生于ClassLoader類,父類加載器為擴(kuò)展類加載器。

          ????它負(fù)責(zé)加載環(huán)境變量classpath或系統(tǒng)屬性java.class.path指定路徑下的類庫,該類加載是程序中默認(rèn)的類加載器,一般來說,Java應(yīng)用的類都是由它來完成加載,通過ClassLoader#getSystemclassLoader() 方法可以獲取到該類加載器。

          2.2.2、用戶自定義類加載器

          ????在Java的日常應(yīng)用程序開發(fā)中,類的加載幾乎是由上述3種類加載器相互配合執(zhí)行的,在必要時,我們還可以自定義類加載器,來定制類的加載方式。為什么要自定義類加載器?我們自定義類加載器的主要有四個原因:

          1. 隔離加載類。

          2. 修改類的加載方式。

          3. 拓展加載源。

          4. 防止源碼泄露。

          ????用戶自定義類加載器實現(xiàn)步驟:

          1. 開發(fā)人員可以通過繼承抽象類ava.lang.ClassLoader類的方式,實現(xiàn)自己的類加載器,以滿足一些特殊的需求。

          2. 在JDK1.2之前,在自定義類加載器時,總會去繼承ClassLoader類并重寫loadClass() 方法,從而實現(xiàn)自定義的類加載類,但是在JDK1.2之后已不再建議用戶去覆蓋loadclass() 方法,而是建議把自定義的類加載邏輯寫在findClass()方法中。

          3. 在編寫自定義類加載器時,如果沒有太過于復(fù)雜的需求,可以直接繼承URLClassLoader類,這樣就可以避免自己去編寫findClass() ?方法及其獲取字節(jié)碼流的方式,使自定義類加載器編寫更加簡潔。

          2.3、ClassLoader的使用說明

          ??? ClassLoader類是一個抽象類,其后所有的類加載器都繼承自ClassLoader(不包括啟動類加載器)。

          方法名稱描述
          getParent()返回該類加載器的超類加載器
          loadClass(String name)加載一個名為name的類,返回一個java.lang.Class的實例
          findClass(String name)查找一個名為name的類,返回一個java.lang.Class的實例
          findloadedClass(String name)查找名稱為name的已經(jīng)被加載過的類,返回一個java.lang.Class的實例
          defineClass(String name , byte[] b , int off , int len)把字節(jié)數(shù)組b中的內(nèi)容轉(zhuǎn)化為一個Java類,返回一個java.lang.Class的實例
          resloveClass(Class c)指定連接一個Java類

          ????sun.misc.Launcher 它是一個java虛擬機(jī)的入口應(yīng)用。

          ????我們?nèi)绻氆@取一個ClassLoader,大致有四種途徑。

          方式一:獲取當(dāng)前的ClassLoader

          clazz.getClassLoader()
          復(fù)制代碼

          方式二:獲取當(dāng)前線程上下文的ClassLoader

          	Thread.currentThread().getContextClassLoader()
          復(fù)制代碼

          方式三:獲取系統(tǒng)的ClassLoader

          ClassLoader.getSystemClassLoader()
          復(fù)制代碼

          方式四:獲取調(diào)用者的ClassLoader

          DriverManager.getCallerClassLoader()
          復(fù)制代碼

          2.4、雙親委派機(jī)制

          ??? Java虛擬機(jī)對class文件采用的是按需加載的方式,也就是說當(dāng)需要使用該類時才會將它的class文件加載到內(nèi)存生成class對象。而且加載某個類的class文件時,Java虛擬機(jī)采用的是雙親委派模式,即把請求交由父類處理,它是一種任務(wù)委派模式。

          ????他的工作原理大致是這樣:

          1. 當(dāng)一個類加載器收到了加載類的請求時,他并不會先去自己加載,而是把這個請求委托給弗雷德加載器去進(jìn)行執(zhí)行。

          2. 如果父類加載器還存在其他的父類加載器,就會進(jìn)一步向上委托,一次遞歸,直到請求最終到達(dá)頂層的啟動類加載器。

          3. 如果父類加載器可以完成這個類的加載任務(wù),那么就會成功返回。假如父類加載器無法完成加載這個類的任務(wù),子類加載器才會嘗試去自己加載。

          2.4.1、大白話解釋雙親委派機(jī)制

          ????假如有一個小孩,他有一個又酸又硬的蘋果,這個時候家里有奶奶和媽媽。

          2.4.1.1、父類成功加載

          2.4.1.2、父類加載失敗

          2.4.2、證明雙親委派的存在

          ????我們在自己的項目中新建一個包名為java.langString類,一定要是JDK8,不能是JDK11,否則無法驗證

          package java.lang;

          /**
          * @Description 這是我們自己定義的Stirng,和java官方的String同包同名
          * @Author XiaoLin
          * @Date 2021/8/28 16:14
          */

          public class String {
          // 在對象初始化之前就會執(zhí)行
          static {
          System.out.println("我是XiaoLin定義的String");
          }

          }
          復(fù)制代碼

          我們再新建一個測試類

          package cn.linstudy;

          /**
          * @Description
          * @Author XiaoLin
          * @Date 2021/8/28 16:15
          */

          public class TestString {

          public static void main(String[] args) {
          java.lang.String str = new java.lang.String();
          System.out.println("我是XiaoLin");
          }
          }
          復(fù)制代碼

          ????我們執(zhí)行完以后,發(fā)現(xiàn)并沒有打印我們靜態(tài)代碼塊里面的代碼,說明執(zhí)行的并不是我們定義的Stirng類,而是Java官方的Stirng類。

          ????我們在Stirng類中寫一個main方法,執(zhí)行一下。

          package java.lang;

          /**
          * @Description 這是我們自己定義的Stirng,和java官方的String同包同名
          * @Author XiaoLin
          * @Date 2021/8/28 16:14
          */

          public class String {
          static {
          System.out.println("我是XiaoLin定義的String");
          }

          public static void main(String[] args) {
          System.out.println("Hello XiaoLin");
          }
          }
          復(fù)制代碼

          ????發(fā)現(xiàn)報錯了,他說找不到main方法,再次說明了說明執(zhí)行的并不是我們定義的Stirng類,而是Java官方的Stirng類。

          2.4.3、雙親委派機(jī)制的優(yōu)勢

          ????既然JDK搞了一個雙親委派機(jī)制,那么肯定是有他獨特的優(yōu)勢,他的優(yōu)勢有兩點:

          1. 避免類的重復(fù)加載,只要有一個類加載器加載了這個類,那么這個類就不會被其他類加載器加載,防止類被重復(fù)加載。

          2. 保護(hù)程序安全,防止核心的API被篡改。我們舉個例子,自定一個類,在Java.lang包下。

          package java.lang;

          /**
          * @Description
          * @Author XiaoLin
          * @Date 2021/8/28 16:34
          */

          public class SweetCode {

          public static void main(String[] args) {
          System.out.println("Hello SweetCode");
          }
          }
          復(fù)制代碼

          2.4.4、沙箱安全機(jī)制

          ????我們自己自定義了一個String類,但是在加載自定義String類的時候會率先使用引導(dǎo)類加載器加載,而引導(dǎo)類加載器在加載的過程中會先加載jdk自帶的文件(rt.jar包中java\lang\String.class),報錯信息說沒有main方法,就是因為加載的是rt.jar包中的string類。這樣可以保證對java核心源代碼的保護(hù),這就是沙箱安全機(jī)制。


          作者:XiaoLin_Java
          鏈接:https://juejin.cn/post/7021016771545006117
          來源:稀土掘金
          著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。



          瀏覽 42
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青娱乐在线视频国产 | 欧美XXXXBBBB | 国产精品成人久久久久 | 国产盗摄AV | 男人天堂伊人网 |