深刻理解Java虛擬機總結---類初始化過程

https://luhaoaimama1.github.i...java

類的初始化過程git

非法向前引用github

編譯器手機的順序是由語句在源文件中出現的順序決定的,靜態語句塊中只能訪問到定義在靜態語句以前的變量,定義它以後的變量,能夠賦值,但不能訪問bootstrap

public class Test{數組

    static{tomcat

         i=0;jvm

         system.out.print(i);//非法向前引用this

    }spa

    static int i=1;設計

}

(類構造器方法):在jvm第一次加載class文件時調用,若是類或者接口沒有靜態語句塊,也沒有對變量的賦值,那麼編譯器能夠不爲這個類生成方法而且他被加鎖了,既不能作耗時操做。 Tips:若是在此方法中耗時很長,就可能形成多個進程阻塞;

類加載的時機

加載

加載與鏈接階段的驗證動做是交叉進行的

鏈接

驗證

文件格式驗證。是否符合Class文件格式的規範

語義分析。父類,抽象類,接口等。

字節碼驗證

符號引用驗證

準備

正式爲類變量分配內存並設置類變量初始值的階段

public static int value=123;

//final的話  準備階段既123;

//很是量的 static 則準備階段是0;<clinit>類構造方法執行纔會變成123

解析

可選的,loadClass第二個參數來斷定是否須要解釋。這裏的解釋是根據勒種的符號引用查找相應的實體,在把符號引用替換成一個直接引用的過程。

初始化

使用

卸載

類何時才被初始化

只有這6中狀況纔會致使類的類的初始化

建立類的實例,也就是new一個對象

訪問某個類或接口的靜態變量,或者對該靜態變量賦值

調用類的靜態方法

反射(Class.forName("com.lyj.load"))

初始化一個類的子類(會首先初始化子類的父類)

JVM啓動時標明的啓動類,即文件名和類名相同的那個類

全部引用類的方法都不會觸發初始化,稱爲被動引用。

類引用父類的靜態字段,不會致使該類被初始化

類的初始化步驟:

若是這個類尚未被加載和連接,那先進行加載和連接

假如這個類存在直接父類,而且這個類尚未被初始化(注意:在一個類加載器中,類只能初始化一次),那就初始化直接的父類(不適用於接口)

加入類中存在初始化語句(如static變量和static塊),那就依次執行這些初始化語句。

雙親委派模型

Java虛擬器角度僅僅有兩種不一樣的類加載器:

一種啓動類加載器(Bootstrap ClassLoader):C++語言實現是虛擬器自身的一部分;

另外一種是全部其餘的類加載器(java語言,JVM以外 繼承ClassLoader)

更詳細:

!

Bootstrap ClassLoader:負責加載$JAVA_HOME中jre/lib/rt.jar裏全部的class既核心API(ExtClassLoader和AppClassLoader也在此時被加載),由C++實現,不是ClassLoader子類

Extension ClassLoader:負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

App ClassLoader:負責記載classpath中指定的jar包及目錄中class.能夠經過getSystemClassLoader()方法得到

Custom ClassLoader:屬於應用程序根據自身須要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader

加載過程當中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視爲已加載此類,保證此類只全部ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

爲何這麼設計?

類加載器:任何一個類都須要加載它的類加載器和這個類一同確立其在java虛擬機惟一性。每一個類加載器都有類名稱空間。

兩個類是否相同,是由同一個類加載器爲前提下才有意義.相同是指equals、instanceof isAssignalbeFrom isIntance等;

例如類java.lang.Object,他存放在rt.jar中,不管哪一個類加載器加載這個類,最終都是委派給魔性最頂端的啓動類加載器進行加載。所以Object類在程序的各類類加載器環境中都是同一個類。 相反若是沒有使用,各個類加載自行加載的話。那麼系統將出現多個不一樣的Object類,那麼java類型體系中最基本的行爲也沒法保證;

如下是ClassLoader的源碼,實現很簡單

rotected synchronized Class<?> loadClass(String name, boolean resolve)

    throws ClassNotFoundException

    {

    // First, check if the class has already been loaded

    Class c = findLoadedClass(name);

    if (c == null) {

        try {

        if (parent != null) {

            //從父加載器加載

            c = parent.loadClass(name, false);

        } else {

            //從bootstrap loader加載

            c = findBootstrapClassOrNull(name);

        }

        } catch (ClassNotFoundException e) {

                // ClassNotFoundException thrown if class not found

                // from the non-null parent class loader

            }

            if (c == null) {

            // If still not found, then invoke findClass in order

            // to find the class.

            c = findClass(name);

        }

    }

    if (resolve) {

        resolveClass(c);

    }

    return c;

    }

其餘思考的問題

類加載的邏輯應該在哪裏寫?

jdk 1.2以後 已經不提倡用戶覆蓋loadClass方法了,而是應當在本身的類加載邏輯寫到findClass()中。由於loadClass()方法若是加載失敗就會調用本身的findClass()去加載。這樣就能保證 寫出來的類加載器是符合雙親委派模式的

若是依賴特定的擴展包,須要繼承特定的classLoader嗎?

下面的默認構造器, 要在父親是AppClassLoader的基礎上 加載本身的類。否則會破壞雙親的 總結:新的ClassLoader須要舊的去委託。若是不這樣就會致使在同一個類出如今不一樣的ClassLoader中。

protected ClassLoader() {

//getSystemClassLoader()其實就是AppClassLoader

this(checkCreateClassLoader(), getSystemClassLoader());

}

若是類已經 加載過了,那麼應該在哪裏存儲 下一次去驗證是否加載過呢?

能夠經過該ClassLoader中 protect findLoadedClass(name)方法找到。

resolveClass 何時使用

類加載過程總結

獲得類的原始字節數組byte[]。

findClass裏經過defineClass(name, buf, 0, buf.length) 完成類加載。

舉例分析流程

若是一個非ClassPath目錄下的新的數據流類經過新的ClassLoader(NewClassLoader)去加載。

Parent:

NewClassLoader-AppClassLoader->ExtClassLoader

第一次初始化

loadClass:每次findLoadedClass都找不到

NewClassLoader-AppClassLoader->ExtClassLoader

findClass:(loadClass的逆序)

ExtClassLoader->AppClassLoader->NewClassLoader(最後在此define 生成類後loadClass一次)

第二次初始化

loadClass:第一個NewClassLoader中findLoadedClass就找到了

NB技巧:子類能夠公開父類中的protected的方法;

public void findClass_(){

    super.findClass();//protected

}

Demo Code

相關文章
相關標籤/搜索