国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

java中Class類(lèi)裝載流程是怎樣的

發(fā)布時(shí)間:2021-09-27 17:50 來(lái)源:億速云 閱讀:0 作者:柒染 欄目: 開(kāi)發(fā)技術(shù)

java中Class類(lèi)裝載流程是怎樣的,很多新手對此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細講解,有這方面需求的人可以來(lái)學(xué)習下,希望你能有所收獲。

java虛擬機加載class文件過(guò)程如下:

1 類(lèi)裝載的條件

class文件只有在必須要使用的時(shí)候才會(huì )被裝載,java虛擬機不會(huì )無(wú)條件地裝載class類(lèi)型。java虛擬機規定,一個(gè)類(lèi)或接口在初次使用前,必須進(jìn)行初始化。這里的“使用”是指主動(dòng)使用,主動(dòng)使用只有下列幾種情況:

  • 當創(chuàng )建一個(gè)類(lèi)的實(shí)例時(shí),比如使用new關(guān)鍵字或反射、克隆、反序列化。

  • 當調用類(lèi)的靜態(tài)方法時(shí),使用了字節碼invokestatic指令。

  • 當使用類(lèi)或接口的靜態(tài)字段(final常量除外),比如使用getstatic或者putstatic指令。

  • 當使用java.lang.reflect包中的方法反射類(lèi)的方法時(shí)。

  • 當初始化子類(lèi)時(shí),要求先初始化父類(lèi)。

  • 作為啟動(dòng)虛擬機,含有main()方法的那個(gè)類(lèi)。

例1:主動(dòng)使用
public class Parent {
    static {
        System.out.println("Parent init");
    }
    public static int v = 100;
}

public class Child extends Parent {
    static {
        System.out.println("Child init");
    }
}

public class Demo01 {
    public static void main(String[] args) {
        Child c = new Child();
    }
}

以上代碼聲明了3個(gè)類(lèi):Parent、ChildDemo01,ChildParent的子類(lèi)。若Parent被初始化,由代碼中的static語(yǔ)句塊可知,將會(huì )打印“Parent Init”,若Child被初始化,則會(huì )打印“Child Init”,執行Demo01,運行結果:

Parent init
Child init

由此可知,系統首先裝載Parent類(lèi),接著(zhù)裝載Child類(lèi)。

例2:被動(dòng)使用
public class Parent {
    static {
        System.out.println("Parent init");
    }
    public static int v = 100;
}

public class Child extends Parent {
    static {
        System.out.println("Child init");
    }
}

public class Demo02 {
    public static void main(String[] args) {
        System.out.println(Child.v);
    }
}

查看以上代碼,Parent中有靜態(tài)變量v,并且在Demo02中,使用其子類(lèi)Child調用父類(lèi)中的變量。運行以上代碼,輸出結果如下:

Parent init
100

可以看到,雖然在Demo02中直接訪(fǎng)問(wèn)了子類(lèi)對象,但是Child子類(lèi)并未被初始化,只有Parent父類(lèi)被初始化??梢?jiàn),在使用一個(gè)字段時(shí),只有直接定義該字段的類(lèi)才會(huì )被初始化。

注意:雖然Child類(lèi)沒(méi)有被初始化,但是此時(shí)Child類(lèi)已經(jīng)被系統加載,只是沒(méi)有進(jìn)入初始化階段。

使用-XX:+TraceClassLoading參數運行這段代碼,就會(huì )得到以下日志(刪除部分輸出):

oaded java.net.Inet6Address from /Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.net.Inet6Address$Inet6AddressHolder from /Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded jvm.chapter10.Parent from file:/Users/chengyan/IdeaProjects/myproject/DataStructuresAndAlgorithms/out/production/DataStructuresAndAlgorithms/]
[Loaded jvm.chapter10.Child from file:/Users/chengyan/IdeaProjects/myproject/DataStructuresAndAlgorithms/out/production/DataStructuresAndAlgorithms/]
Parent init
100

2 加載類(lèi)

加載類(lèi)處于類(lèi)裝載的第一個(gè)階段。在加載類(lèi)時(shí),java虛擬機必須完成以下工作:

  • 通過(guò)類(lèi)的全名獲取類(lèi)的二進(jìn)制數據

  • 解析類(lèi)的二進(jìn)制數據流為方法區內的數據結構

  • 創(chuàng )建java.lang.Class類(lèi)的實(shí)例,表示該類(lèi)型

對于類(lèi)的二進(jìn)制數據流,虛擬機可能通過(guò)多種途徑產(chǎn)生或獲得,如:class文件,或者jar、zip等歸檔數據包,也可以通過(guò)網(wǎng)絡(luò )加載。

在獲取類(lèi)的二進(jìn)制數據后,java虛擬機就會(huì )處理這些數據,并最終轉為一個(gè)java.lang.Class類(lèi)提供的實(shí)例。

3 驗證類(lèi)

當類(lèi)加載到系統后,就開(kāi)始連續操作,驗證是連續操作的第一步。它的目的是保存加載的字節碼是合法、合理并且符合規范的。驗證的步驟比較復雜,實(shí)際要驗證的項目也繁多,大體上java虛擬機需要做的檢查如下:

4 準備

當一個(gè)類(lèi)驗證難過(guò)時(shí),虛擬機就會(huì )進(jìn)入準備階段。在這個(gè)階段,虛擬機會(huì )為這個(gè)類(lèi)分配相應的內存空間,并設置初始值。java虛擬機各類(lèi)型變量默認值的初始值如下:

注意:java并不支持boolean類(lèi)型,對于boolean類(lèi)型,內部實(shí)現實(shí)際上是int類(lèi)型,由于int類(lèi)型的默認值是0,故對應的boolean類(lèi)型的默認值就是false.

如果類(lèi)存在常量字段(final修飾的字段),那么常量字段也會(huì )在準備階段被賦值上正確的值,這個(gè)賦值屬于java虛擬機的行為,屬于變量的初始化。

5 解析類(lèi)

準備階段后是解析階段。解析階段的工作就是將類(lèi)、接口、字段和方法的符號引用轉為直接引用。

符號引用就是一些字面量的引用,和虛擬機的內部數據結構與內存布局無(wú)關(guān)。在Class類(lèi)文件中,在大量的符號引用,但在運行時(shí),只有符號引用是不夠的,系統需要明確變量、方法等的位置。以方法為例,java虛擬機為每個(gè)類(lèi)都準備了一張方法表,將其所有的方法都列在表中,當需要調用一個(gè)類(lèi)的方法時(shí),只要知道這個(gè)方法在方法表中的偏移量就可以直接調用。通過(guò)解析操作,符號引用可以轉變?yōu)槟夸浄椒ㄔ陬?lèi)的方法表中的位置,從而使得方法被成功調用。

綜上所述,所謂解析,就是將符號引用轉為直接引用,也就是得到類(lèi)或者字段、方法在內存中的指針或者偏移量。

6 初始化

類(lèi)的初始化是類(lèi)裝載的最后一個(gè)階段,如果前面的步驟都沒(méi)有問(wèn)題,表示類(lèi)可以順利裝載到系統中。此時(shí),類(lèi)才會(huì )開(kāi)始執行java字節碼。初始化階段的重要工作是執行類(lèi)的初始化方法 <clinit>。方法<clinit>是由編譯器自動(dòng)生成的,它是由靜態(tài)成員的賦值語(yǔ)句及static語(yǔ)句塊共同產(chǎn)生的。

值得一提的是,對于<clinit>方法,也就是類(lèi)的初始化,虛擬機會(huì )在內部確保其多線(xiàn)程環(huán)境中的安全。也就是說(shuō),當多個(gè)線(xiàn)程試圖初始化同一個(gè)類(lèi)時(shí),只有一個(gè)線(xiàn)程可以進(jìn)入<clinit>方法了(當需要使用這個(gè)類(lèi)時(shí),虛擬機就會(huì )直接返回它已經(jīng)準備好的信息)。

正因為<clinit>方法是帶鎖線(xiàn)程安全的,所以在多線(xiàn)程環(huán)境下進(jìn)行類(lèi)初始化時(shí),可能會(huì )引起死鎖,并且這種死鎖是很難發(fā)現,因為看起來(lái)他們并沒(méi)有可用的鎖信息。

下面的代碼展示了在類(lèi)的初始化時(shí),產(chǎn)生了死鎖線(xiàn)程:

package jvm.chapter10;

class StaticA {
    static {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {

        }
        try {
            Class.forName("jvm.chapter10.StaticB");
        } catch (ClassNotFoundException e) {

        }
        System.out.println("StaticA init OK!");
    }
}

class StaticB {
    static {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {

        }
        try {
            Class.forName("jvm.chapter10.StaticA");
        } catch (Exception e) {

        }
        System.out.println("StaticB init OK");
    }
}

public class Demo03 extends Thread {

    private char flag;

    public Demo03(char flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        try {
            Class.forName("jvm.chapter10.Static" + flag);
        } catch (Exception e) {

        }
        System.out.println(getName() + "over");
    }

    public static void main(String[] args) throws Exception {
        Demo03 loadA = new Demo03('A');
        Demo03 loadB = new Demo03('B');
        loadA.start();
        loadB.start();
        loadA.join();
        loadB.join();
    }
}

以上代碼由3個(gè)類(lèi)組成:StaticA、StaticBDemo03.在Demo03中創(chuàng )建了兩個(gè)線(xiàn)程,線(xiàn)程A試圖初始化StaticA,線(xiàn)程B嘗試初始化StaticB,在StaticA的初始化過(guò)程中,會(huì )嘗試初始化StaticB,同樣在StaticB的初始化過(guò)程中,也初始化 StaticA,這就導致了死鎖。

通過(guò)線(xiàn)程堆棧dump可以得到如下信息:

"Thread-1" #12 prio=5 os_prio=31 tid=0x00007f9dd4853000 nid=0x5703 in Object.wait() [0x0000700004797000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at jvm.chapter10.StaticB.<clinit>(Demo03.java:33)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at jvm.chapter10.Demo03.run(Demo03.java:52)

   Locked ownable synchronizers:
        - None

"Thread-0" #11 prio=5 os_prio=31 tid=0x00007f9dd4801800 nid=0xa803 in Object.wait() [0x0000700004694000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at jvm.chapter10.StaticA.<clinit>(Demo03.java:17)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at jvm.chapter10.Demo03.run(Demo03.java:52)

   Locked ownable synchronizers:
        - None

在這種情況下,系統并沒(méi)有給出足夠的信息來(lái)判定死鎖,但是死鎖確實(shí)存在,我們需要格外小心由類(lèi)的初始化引起的死鎖問(wèn)題。

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

少妇人妻综合久久中文字幕| H漫在线观看| 农村女妓女野外bbw| 亚洲精品无码专区久久久| 全部免费的毛片在线看| 18禁美女裸身无遮挡免费网站|