帶着問題學習是最高效的,本次咱們將嘗試回答如下問題:html
答案放在文章的最後,來不及看原理也能夠直接跳到最後直接看答案。java
類的生命週期相信你們已經耳熟能詳,就像下面這樣:面試
不過這東西老是背了就忘,忘了又背,就像馬什麼梅同樣,對吧?數組
其實理解以後,基本上就不會再忘了。緩存
加載主要作三件事:安全
總的來說,這一步就是經過類加載器把類讀入內存。須要注意的是,第三步雖然生成了對象,但並不在堆裏,而是在方法區裏。數據結構
鏈接分爲三步,通常面試都比較喜歡問準備這一步。jvm
顧名思義,檢查Class文件的字節流中包含的信息是否符合當前虛擬機的要求。學習
這一步中將爲靜態變量和靜態常量分配內存,並賦值。.net
須要注意的是,靜態變量只會給默認值。好比下面這個:
public static int value = 123;
此時賦給value的值是0,不是123。
靜態常量(static final修飾的)則會直接賦值。好比下面這個:
public static final int value = 123;
此時賦給value的值是123。
解析階段就是jvm將常量池的符號引用替換爲直接引用。
恩......啥是常量池?啥是符號引用?啥是直接引用?
常量池咱們放在jvm內存結構裏說。先來講下什麼是符號引用和直接引用。
假設有一個Worker類,包含了一個Car類的run()方法,像下面這樣:
class Worker{ ...... public void gotoWork(){ car.run(); //這段代碼在Worker類中的二進制表示爲符號引用 } ...... }
在解析階段以前,Worker類並不知道car.run()這個方法內存的什麼地方,因而只能用一個字符串來表示這個方法。該字符串包含了足夠的信息,好比類的信息,方法名,方法參數等,以供實際使用時能夠找到相應的位置。
這個字符串就被稱爲符號引用。
在解析階段,jvm根據字符串的內容找到內存區域中相應的地址,而後把符號引用替換成直接指向目標的指針、句柄、偏移量等,這以後就能夠直接使用了。
這些直接指向目標的指針、句柄、偏移量就被成爲直接引用。
類的初始化的主要工做是爲靜態變量賦程序設定的初值。
還記得上面的靜態變量嗎:
public static int value = 123;
通過這一步,value的值終因而123了。
總結以下圖:
Java虛擬機規範中嚴格規定了有且只有五種狀況必須對類進行初始化:
除了以上這五種狀況,其餘任何狀況都不會觸發類的初始化。
好比下面這幾種狀況就不會觸發類初始化:
在上面我們曾經說到,加載階段須要「經過一個類的全限定名來獲取描述此類的二進制字節流」。這件事情就是類加載器在作。
jvm自帶三種類加載器,分別是:
他們的繼承關係以下圖:
雙親委派機制工做過程以下:
當前ClassLoader首先從本身已經加載的類中查詢是否此類已經加載,若是已經加載則直接返回原來已經加載的類。每一個類加載器都有本身的加載緩存,當一個類被加載了之後就會放入緩存,等下次加載的時候就能夠直接返回了。
當前classLoader的緩存中沒有找到被加載的類的時候,委託父類加載器去加載,父類加載器採用一樣的策略,首先查看本身的緩存,而後委託父類的父類去加載,一直到bootstrp ClassLoader.
當全部的父類加載器都沒有加載的時候,再由當前的類加載器加載,並將其放入它本身的緩存中,以便下次有加載請求的時候直接返回。
爲啥要搞這麼複雜?本身處理很差嗎?
雙親委派的優勢以下:
「雙親委派」機制只是Java推薦的機制,並非強制的機制。
好比JDBC就打破了雙親委派機制。它經過Thread.currentThread().getContextClassLoader()獲得線程上下文加載器來加載Driver實現類,從而打破了雙親委派機制。
至於爲何,之後再說吧。
如今,咱們能夠回答文章開頭提出的問題了。儘可能在理解的基礎上回答,不須要死記硬背。
什麼是類的加載?
JVM把經過類名得到類的二進制流以後,把類放入方法區,並建立入口對象的過程被稱爲類的加載。通過加載,類就被放到內存裏了。
哪些狀況會觸發類的初始化?
類在5種狀況下會被初始化:
第一,假如這個類是入口類,他會被初始化。
第二,使用new建立對象,或者調用類的靜態變量,類會被初始化。不過靜態常量不算。
第三,經過反射獲取類,類會被初始化
第四,若是子類被初始化,他的父類也會被初始化。
第五,使用jdk1.7的動態語言支持時,調用到靜態句柄,也會被初始化。
講一下JVM加載一個類的過程
同問題1。不過這裏也能夠問下面試官是否是想問類的生命週期。若是是問類的生命週期,能夠回答有」加載、鏈接、初始化、使用、卸載「五個階段,鏈接又能夠分爲」校驗、準備、解析「三個階段。
何時會爲變量分配內存?
在準備階段爲靜態變量分配內存。
JVM的類加載機制是什麼?
雙親委派機制,類加載器會先讓本身的父類來加載,父類沒法加載的話,纔會本身來加載。
雙親委派機制能夠打破嗎?爲何
能夠打破,好比JDBC使用線程上下文加載器打破了雙親委派機制。緣由是JDBC只提供了接口,並無提供實現。這個問題能夠再看下引用文獻的內容。