1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官再問你如何破壞雙親委派,就把這篇文章扔給他

        共 3955字,需瀏覽 8分鐘

         ·

        2021-05-23 15:16



        前言

        我們每天都在寫Java代碼,最常見的User.java這種文件,但是這種文件是如何被虛擬機識別的呢,你有沒有思考過這個過程

        首先我們寫的Java文件會被編譯成class文件,因為機器不認識getName這種,機器只認識010101

        編譯完成的class文件會被加載到虛擬機中,用于完成我們的任務,那這個加載是什么時候開始呢,加載的過程是什么樣子的呢


        類加載時機

        先來肝個圖,類的加載過程

        類從被加載到虛擬機開始,到卸載出內存為止,它的整個的生命周期包括:加載、驗證、準備、解析、初始化、使用和卸載七個階段

        而驗證、準備、解析三個階段被統(tǒng)稱為連接階段

        類的加載時機,也就是類是在何時開始加載這一過程的呢

        這一點虛擬機并沒有明確規(guī)范,虛擬機可以自由實現(xiàn),但是對于其中有一個步驟叫做初始化,虛擬機規(guī)范則是嚴格規(guī)定了有且只有5種情況立即對類進行初始化,而在此之前的過程也需要提前開始

        • 遇到new、getstatic、putstatic或者invokestatic這四條字節(jié)碼指令時,生成這四個字節(jié)碼最常見的Java代碼場景就是使用new關鍵字實例化對象的時候、讀取或者設置一個類的靜態(tài)字段,以及調用一個類的靜態(tài)方法的時候

        • 使用java.lang.reflect包的方法進行反射調用的時候,類如果沒有初始化則觸發(fā)初始化

        • 初始化一個類的時候,發(fā)現(xiàn)其父類未進行初始化,需要先初始化父類

        • JVM啟動時用戶指定執(zhí)行包含main方法的類,會先被初始化

        • 當使用JDK1.7的動態(tài)語言支持的時候,如果一個java.lang.invoke.MethodHandle實例最后的解析結果是REF_getStatic、REF_putStatic、REF_putStatic、REF_invokeStatic的方法句柄的時候,并且這個方法句柄所對應的類沒進行初始化,需要先初始化


        類加載過程

        類加載過程,其實這是屬于純理論知識,大家不知道這些工作中照常開發(fā),為什么呢,因為一般這種東西在實際工作中確實也派不上什么用場

        那我看這個還有啥用啊,拜拜了您嘞

        話不是這么說的,仔仔,你不能說你用不到他就一點也不去了解他,有一句話叫做,書到用時方很少,多讀讀書,學學這些基礎知識,有利于你更好的打牢你的基礎

        在外面面試時也能夠神擋殺神,佛擋殺佛

        面試官還就愛問這玩意,這玩意能看出你學習的深度,有沒有自己去思考過這些東西

        類加載過程:加載、連接、初始化

        加載過程

        將編譯之后的Class文件加載至虛擬機,并存儲在方法區(qū)(不知道為什么存儲在方法區(qū)的仔仔,可以去我的面試官問我平時寫的Bug的存儲位置(逃逸分析、標量替換、鎖消除)這一篇中學一波拉

        連接過程

        連接其實也是被分為了驗證、準備、解析三部分組成,驗證就是保證該Class文件中的信息是否符合Java虛擬機的要求,是否安全(可能會做出危害虛擬機的行為)準備就是為類變量分配內存,并設置類變量的初始值,不包含實例變量的內存,實例變量的內存將會被分配到堆中

        這里的初始值指的是數(shù)據(jù)類型的零值,并非程序員設置的值,比如static int i = 1;此時得到的i是0,并非我們想要的1

        接下來就是連接過程的解析階段,這一階段就是將常量池中的符號引用替換為直接引用(內存地址)的過程

        解析階段啥玩意啊,說了個寂寞,符號引用是啥,直接引用又是啥

        符號引用,就是以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用的時候能夠無歧義的定位到目標即可

        直接引用,可以直接指向目標的指針、相對偏移量或者是一個能夠間接定位到目標的句柄,直接引用是和內存布局相關的,同一個符號引用在不同虛擬機翻譯出來的直接引用一般不同,因為地址不一樣

        如果有了直接引用,則引用的目標必定已經(jīng)存在于內存中了

        初始化

        初始化是類加載的最后一步,前面的類加載過程中,除了在加載階段用戶應用程序可以通過自定義類加載器參與之外,其余的動作其實都是由虛擬機主導和控制的

        而初始化階段才是真正開始執(zhí)行程序中代碼的步驟,也就是上面說的i賦值為1的過程,初始化類變量,加載類的靜態(tài)語句塊的過程

        在準備階段賦值過一次了,那次賦值是系統(tǒng)要求的初始值,跟我們個人的設定無關,而初始化的賦值才是真正根據(jù)程序員設計而主導的初始化

        使用和卸載

        使用類的階段就是大家new對象的過程,我們會使用到各種類型對象,以及使用完畢對這個類型的卸載,卸載一般發(fā)生在程序關閉的時候

        程序正常執(zhí)行結束、遇到異常關閉、或者操作系統(tǒng)出問題導致程序關閉這些都會卸載這些類的加載


        雙親委派

        類加載器

        從JVM的角度看,類加載器主要有兩類:

        • Bootstrap ClassLoader和其他類加載,Bootstrap ClassLoader是C++語言實現(xiàn),是虛擬機自身的一部分;

        • 其他類加載器都是Java語言實現(xiàn),不屬于虛擬機,全部繼承自抽象類java.lang.ClassLoader

        從Java開發(fā)者的角度看,需要了解類加載器的雙親委派模型,如下圖所示:

        Bootstrap ClassLoader:啟動類加載器,這個類加載器將負責存放在/lib目錄中,并且是虛擬機會識別的jar類庫加載到內存中。更直白點說,就是我們常用的java.lang開頭的那些類,一定是被Bootstrap ClassLoader加載的

        Extension ClassLoader:擴展類加載器,它負責加載/lib/ext目錄中的、或者被java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫。

        Application ClassLoader:應用程序類加載器,它負責加載用戶CLASSPATH環(huán)境變量指定的路徑中的所有類庫。如果應用程序中沒有自定義過自己的類加載器,這個就是一個Java程序中默認的類加載器。

        用戶自定義的類加載器:用戶在需要的情況下,可以實現(xiàn)自己的自定義類加載器,一般而言,在以下幾種情況下需要自定義類加載器

        • 隔離加載類。某些框架為了實現(xiàn)中間件和應用程序的模塊的隔離,就需要中間件和應用程序使用不同的類加載器

        • 修改類加載的方式。類加載的雙親委派模型并不是強制的,用戶可以根據(jù)需要在某個時間點動態(tài)加載類

        • 擴展類加載源,例如從數(shù)據(jù)庫、網(wǎng)絡進行類加載

        • 防止源代碼泄露。Java代碼很容易被反編譯和篡改,為了防止源碼泄露,可以對類的字節(jié)碼文件進行加密,并編寫自定義的類加載器來加載自己的應用程序的類

        聽說過雙親委派嗎

        至于雙親委派,我覺得可能很多人都聽說過,或者說簡單的了解過,大魚這里也繼續(xù)給大家啰嗦一下

        如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把請求委托給父加載器去完成,依次向上,因此,所有的類加載請求最終都應該被傳遞到頂層的啟動類加載器中,只有當父加載器在它的搜索范圍中沒有找到所需的類時,即無法完成該加載,子加載器才會嘗試自己去加載該類

        見過一個問題,說為什么叫雙親委派,而不是單親委派,在Java中應該是單繼承的,哪里來的雙親呢

        我個人的猜測是一個類加載大概會向上委托兩次,兩次來讓父加載器加載,所以是雙親委派,當然這也是個人猜測,網(wǎng)上查閱了很多資料,也是模棱兩可,其實大家也不必要對這種問題糾結,聽聽就好

        雙親委派可以破壞嗎

        這個問題很經(jīng)典,面試如果問到JVM,這個問題大概率會被問到,這個時候就到了你裝*的時候了,這個時候就輪到給面試官好感,以及漲工資的時刻

        回答問題,一定要循序漸進,按照條理思路來分析,這樣會大大增加你在面試官心中的好感,別問我怎么知道的

        當然可以破壞了,我們知道類的加載方式默認是雙親委派,如果我們有一個類想要通過自定義的類加載器來加載這個類,而不是通過系統(tǒng)默認的類加載器,說白了就是不走雙親委派那一套,而是走自定義的類加載器

        我們知道雙親委派的機制是ClassLoader中的loadClass方法實現(xiàn)的,打破雙親委派,其實就是重寫這個方法,來用我們自己的方式來實現(xiàn)即可

        當然這里要注意一下,Object.class這是對象的頂級類,改變類的類加載器的時候要注意,如果全部改了,Object.class就找不到了,加載不了了

        所以呢,這里重寫的時候,要注意分類解決,把你想要通過自定義類加載器加載的和想通過默認類加載器加載的分隔開


         


        求贊



         

        好了,以上就是全部內容了,我是小魚仙,你們的學習成長小伙伴

                                     

        我希望有一天能夠靠寫字養(yǎng)活自己,現(xiàn)在還在磨練,這個時間可能會有很多年,感謝你們做我最初的讀者和傳播者。請大家相信,只要給我一份愛,我終究會還你們一頁情的。

        再次感謝大家能夠讀到這里,我后面會持續(xù)的更新技術文章以及一些記錄生活的靈魂文章,如果覺得不錯的,覺得大魚同學有點東西的話,求點贊、關注、分享三連

        哦,對了!后續(xù)的更新文章我都會及時放到這里,歡迎大家點擊觀看,都是干貨文章啊,建議收藏,以后隨時翻閱查看

        https://github.com/DayuMM2021/Java

         

        推薦閱讀


        ● 面試官問我:你確定用了BigDecimal后,計算結果一定精確?

           ● 這個GitHub地址,真香

        ● 消息隊列入門

           ● 搞懂什么是RocketMQ


        瀏覽 71
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲电影在线 | 欧美日韩亚洲国产 | 国产91无码网站在线观看 | 人妻中文字幕一区二区三区三区 | 肏逼视频免费看 | 欧美一级aaa | 婷婷久久综合 | 欧美久久片 | 逼特逼视频m3m8 | 国产自偷自拍 |