取得類的二進制流java
轉化爲方法區的數據結構設計模式
在java堆中生成對應的 java.lang.Class對象緩存
驗證安全
目的:保證Class流的格式是否正確數據結構
文件格式是否正確、元數據驗證、字節碼驗證、符號引用驗證ide
準備spa
分配內存,併爲類設置初始值(在方法區中)線程
public static int v=1;
在準備階段中,v會被設置爲0
在初始化的<clinit>中才會被設置爲1
對於static final類型,在準備階段就會被賦上正確的值
public static final int v=1;設計
解析3d
符號引用替換爲直接引用
符號引用 :字符串 引用對象不必定被加載
直接引用:指針或者地址偏移量 引用對象必定在內存
執行類的構造器<clinit> :static 變量賦值 static{}語句
子類的<clinit> 調用前,保證父類的 <clinit>被調用
<clinit>是線程安全的
ClassLoader 是一個抽象類
ClassLoader的實例將讀入java字節碼類裝載到JVM
ClassLoader能夠定製,知足不通字節碼流獲取的方式
ClassLoader負責類加載過程的加載階段
public Class<?> loadClass(String name) throws ClassNotFoundException
載入並返回一個Class
protected final Class<?> defineClass(byte[] b, int off, int len)
定義一個類,不公開調用
protected Class<?> findClass(String name) throws ClassNotFoundException
loadClass回調該方法,自定義ClassLoader的推薦作法
protected final Class<?> findLoadedClass(String name)
尋找已經加載的類
BootStrap ClassLoader (啓動ClassLoader) 這個父類 沒有 ClassLoader
Extension ClassLoader (擴展ClassLoader)
App ClassLoader (應用ClassLoader/系統ClassLoader)
Custom ClassLoader(自定義ClassLoader)
Java中ClassLoader的加載採用了雙親委託機制,採用雙親委託機制加載類的時候採用以下的幾個步驟:
1. 當前ClassLoader首先從本身已經加載的類中查詢是否此類已經加載,若是已經加載則直接返回原來已經加載的類。
每一個類加載器都有本身的加載緩存,當一個類被加載了之後就會放入緩存,等下次加載的時候就能夠直接返回了。
2. 當前classLoader的緩存中沒有找到被加載的類的時候,委託父類加載器去加載,父類加載器採用一樣的策略,首先查看本身的緩存,而後委託父類的父類去加載,一直到bootstrp ClassLoader.
3. 當全部的父類加載器都沒有加載的時候,再由當前的類加載器加載,並將其放入它本身的緩存中,以便下次有加載請求的時候直接返回。
說到這裏你們可能會想,Java爲何要採用這樣的委託機制?理解這個問題,咱們引入另一個關於Classloader的概念「命名空間」, 它是指要肯定某一個類,須要類的全限定名以及加載此類的ClassLoader來共同肯定。也就是說即便兩個類的全限定名是相同的,可是由於不一樣的ClassLoader加載了此類,那麼在JVM中它是不一樣的類。明白了命名空間之後,咱們再來看看委託模型。採用了委託模型之後加大了不一樣的 ClassLoader的交互能力,好比上面說的,咱們JDK本生提供的類庫,好比hashmap,linkedlist等等,這些類由bootstrp 類加載器加載了之後,不管你程序中有多少個類加載器,那麼這些類其實都是能夠共享的,這樣就避免了不一樣的類加載器加載了一樣名字的不一樣類之後形成混亂。
Java除了上面所說的默認提供的classloader之外,它還允許應用程序能夠自定義classloader,那麼要想自定義classloader咱們須要經過繼承java.lang.ClassLoader來實現,
這裏咱們須要注意一點就是public Class<?>loadClass(String name) throws ClassNotFoundException沒有被標記爲final,也就意味着咱們是能夠override這個方法的,也就是說雙親委託機制是能夠打破的。
在應用工做的時候,進行修改java文件,進行動態編譯,不須要中止。