成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

【JVM類加載】類的初始化和類加載器雙親委托機制

開發 后端
類被加載后,就進入鏈接階段。鏈接就是將已經讀入到內存的類的二進制數據合并到虛擬機的運行時環境中去。

以此遞進,先加載test9調用子類,先初始化父類,類的初始化7中之一。

有兩種類型的類加載器

java虛擬機自帶的加載器

  • 根類加載器(Bootstrap)
  • 擴展類加載器(Extension)
  • 系統(應用)類加載器(System)(2,3都屬于Launcher類的內部類)

用戶自定義的類加載器

  • java.lang.ClassLoader的子類。
  • 用戶可以定制類的加載方式。
  • 包括自定義類加載器在構造的時候在構造方法中傳入了一個父類加載。

類的加載器并不需要等到某個類被“首次主動使用”時再加載它(個人理解 加載不一定初始化,初始化一定加載)。

類的加載

  • jvm規范允許類加載器在預料某個類將要被使用時就預先加載他,如果在預先加載的過程中遇到了.class文件缺失或存在錯誤,類加載器必須在程序首次主動使用該類時才報告錯誤(LinkageError錯誤)。
  • 果這個類一直沒有被程序主動使用,那么類加載器就不會報告錯誤。

類被加載后,就進入鏈接階段。鏈接就是將已經讀入到內存的類的二進制數據合并到虛擬機的運行時環境中去。

類的初始化類的初始化步驟

  • 假如這個類還沒有被加載和連接,那就先進行加載和連接。
  • 假如類存在直接父類,并且這個父類還沒有被初始化,那就先初始化直接父類。
  • 假如類中存在初始化語句,那就依次執行這些初始化語句。

類的初始化時機

主動使用(7種,重要)除了七種情形,其他使用java類的方式都被看做是被動使用,不會導致類的初始化。

初始化時機

jdk1.8在之后首次調用接口的靜態方法和default方法也會導致接口初始化。

初始化時機

示例:

public class Test5 {
    public static void main(String[] args) {
          //驗證初始化一個類時,并不會先初始化它所實現的接口
//        System.out.println(MyChild5.b);
        //驗證初始化一個接口時,并不會初始化它所實現的接口
        System.out.println(MyChild5_1.thread);
    }
}
interface MyParcnt5{

    public static Thread thread = new Thread(){
        {
            System.out.println("MyParcnt5 invoked");
        }
    };
    public static final int a = 5;
}
//interface MyChild5 extends MyParcnt5{
//
//    public static int b = new Random().nextInt(4);
//}
class MyChild5 implements MyParcnt5{
    //此時MyChild5 被加載并沒有被初始化  (加載不一定初始化,初始化一定加載)
    public static int b = 6;
}
interface MyParcnt5_1{
    public static Thread thread = new Thread(){
        {
            System.out.println("MyParcnt5_1 invoked");
        }
    };
}
interface MyChild5_1 extends MyParcnt5_1 {
    public static Thread thread = new Thread(){
        {
            System.out.println("MyChild5_1 invoked");
        }
    };
}

類加載器雙親委托機制詳解

他們之間存在的是包含關系 不是繼承關系樹形結構。

public abstract class ClassLoader {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    // The parent class loader for delegation
    // Note: VM hardcoded the offset of this field, thus all new fields
    // must be added *after* it.
    private final ClassLoader parent;

ClassLoader中有一個成員變量定義著雙親 因為除了根類加載器每個加載器都繼承于ClassLoder 所以每個ClassLoaderd都存在著對應的雙親 所以他們之間存在的是包含關系 不是繼承關系樹形結構。

加載過程

在雙親委托機制中,各個加載器按照父子關系形成了樹形結構,除了根類加載器之外,其余的類加載器都有且只有一個父加載器。

加載過程

每個類都需要類加載器去加載,如果有父類,先讓父類去加載,如此向上追溯,直到根類加載器,然后根類加載器嘗試去加載,加載成功賊結束,加載失敗,又往下,一層層的嘗試去加載,最終如果都沒有加載成功則報錯。

加載方式

回顧之前學的知識點。

public class Test7 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> clazz = Class.forName("java.lang.String");
        System.out.println(clazz.getClassLoader());//獲取類加載器,如果是Bootstrap ClassLoader 根加載器加載可能會返回null

        Class<?> clazs = Class.forName("com.example.demo.com.jvm.C");
        System.out.println(clazs.getClassLoader());//sun.misc.Launcher$AppClassLoader@18b4aac2 基本上工程編寫的類都是由系統(應用)加載器AppClassLoader加載的
    }
}

class C {

}

打印結果:

null
sun.misc.Launcher$AppClassLoader@18b4aac2
class FinalTest {
    public static final int x = 3;
//    public static final int x = new Random().nextInt(3);

    static {
        System.out.println("FinalTest static block");
    }
}

public class Test8 {

    public static void main(String[] args) {
        System.out.println(FinalTest.x);
    }
}
/*
    public static final int x = 3; 時 此時在編譯階段 常量x 會被放進Test8的常量池 直接拿來使用 		    FinalTest 并不會被初始化

    3
 */
/*
    public static final int x = new Random().nextInt(3);時 new Random().nextInt(3)生成隨機數實在運行時生成的 所以 Test8和FinalTest  有聯系 此時FinalTest類會被加載

    FinalTest static block
    1
*/
class Parent {
    static int a = 3;
    static {
        System.out.println("Parent static block");
    }
}
class Child extends Parent {
    static int b = 4;
    static {
        System.out.println("Child static block");
    }
}
public class Test9 {
    static {
        System.out.println("Test9 static block");
    }
    public static void main(String[] args) {
        System.out.println(Child.b);
    }
}

以此遞進 先加載test9 調用子類 先初始化父類 類的初始化7種之一。

/*
以此遞進 先加載test9 調用子類 先初始化父類 類的初始化7中之一
 Test9 static block
 Parent static block
 Child static block
 4
 */
class Parent1 {
    static int a = 3;
    static {
        System.out.println("Parent static block");
    }

}
class Child1 extends Parent1 {
    static int b = 4;
    static {
        System.out.println("Child static block");
    }
}
public class Test10 {
    static {
        System.out.println("Test10 static block");
    }
    public static void main(String[] args) {
        Parent1 parent1;
        System.out.println("===========");
        parent1 = new Parent1();
        System.out.println("===========");
        System.out.println(parent1.a);
        System.out.println("===========");
        System.out.println(Child1.b);
    }
}

類只會首次加載才會初始化。

/*
類只會首次加載才會初始化
Test10 static block
===========
Parent static block
===========
3
===========
Child static block
4
 */
class Parent3 {
    static int a = 3;
    static {
        System.out.println("Parent3 static block");
    }
    static void doSomething() {
        System.out.println("do doSomething");
    }
}
class Child3 extends Parent3 {

    static {
        System.out.println("Child3 static block");
    }
}
public class Test11 {
    public static void main(String[] args) {
        System.out.println(Child3.a); //類名.父類靜態變量和靜態方法 表示對父類的主動使用 此時子類并不初始化
        System.out.println("---------------");
        Child3.doSomething();
    }
}

類名.父類靜態變量和靜態方法 表示對父類的主動使用 此時子類并不初始化。

//調用ClassLoader類的loadClass方法加載一個類,并不是對類的主動使用,不會導致類的初始化

public class Test12 {

    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader loder = ClassLoader.getSystemClassLoader(); //獲取系統加載器

        Class<?> aClass = loder.loadClass("com.example.demo.com.jvm.CL");//加載對應類 除卻7種都是被動使用 不會初始化

        System.out.println(aClass);

        System.out.println("-----------------");

        Class<?> aClass1 = Class.forName("com.example.demo.com.jvm.CL");//7種之一
        System.out.println(aClass1);

    }
}

只有反射初始化CL了 調用ClassLoader類的loadClass方法加載一個類,并不是對類的主動使用,不會導致類的初始化。

/*
只有反射初始化CL了 調用ClassLoader類的loadClass方法加載一個類,并不是對類的主動使用,不會導致類的初始化

class com.example.demo.com.jvm.CL
-----------------
Class cl
class com.example.demo.com.jvm.CL
 */

不同的類加載器作用與動作分析

隱式加載: 程序在運行過程中碰到通過new等方式生成對象時,隱式調用類裝載器加載對應的類到jvm中。

顯式裝載: 通過class.forname()等方法,顯示加載需要的類。

類加載的動態體現

  • 一個應用程序總是由n多個類組成,Java程序啟動時,并不是一次把所有的類全部加載后再運行,它總是先把保證程序運行的基礎類一次性加載到jvm中,其它類等到jvm用到的時候再加載,這樣的好處是節省了內存的開銷,因為java最早就是為嵌入式系統而設計的,內存寶貴,這是一種可以理解的機制,而用到時再加載這也是java動態性的一種體現。
  • public static ClassLoader getSystemClassLoader();獲取系統類加載器。

返回用于委派的系統類加載器getParent() 返回父類加載器進行委派。

public class Test13 {
    public static void main(String[] args) {
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();//獲取系統類加載

        System.out.println(classLoader);

        while (null != classLoader) {
            classLoader = classLoader.getParent(); //獲取父加載器 因為使用根加載器時 返回值是用null來表示 所以循環結束
            System.out.println(classLoader);
        }
    }
}
/*
jdk自帶 的三個類加載器
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1eb44e46
null 并沒有繼承classLoader
*/
public class Test14 {
    public static void main(String[] args) throws IOException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();//獲取當前線程的上下文類加載器 通常是獲取那個用于啟動應用的類加載器

        String res = "com/example/demo/com/jvm.Test13.class";

        Enumeration<URL> resource = classLoader.getResources(res);//獲取 類的資源
        while (resource.hasMoreElements()) {
            URL url = resource.nextElement();
            System.out.println(url);
        }

        System.out.println("--------獲取類加載器的有對應的的類-----------");

        Class<Test14> test14Class = Test14.class;
        System.out.println(test14Class.getClassLoader()); //sun.misc.Launcher$AppClassLoader@18b4aac2

    }
}

獲取類加載器的幾種方法。

獲取類加載的幾種方式

責任編輯:姜華 來源: 今日頭條
相關推薦

2024-03-08 08:26:25

類的加載Class文件Java

2012-02-09 10:31:17

Java

2023-10-31 16:00:51

類加載機制Java

2024-12-04 09:01:55

引導類加載器C++

2021-07-05 06:51:43

Java機制類加載器

2011-07-22 17:46:43

java

2020-10-26 11:20:04

jvm類加載Java

2020-11-02 07:02:10

加載鏈接初始化

2024-12-02 09:01:23

Java虛擬機內存

2017-09-20 08:07:32

java加載機制

2017-03-08 10:30:43

JVMJava加載機制

2021-04-29 11:18:14

JVM加載機制

2021-01-06 09:01:05

javaclass

2023-08-02 08:38:27

JVM加載機制

2024-04-09 08:41:41

JVM類加載Java

2011-03-17 09:58:43

Java虛擬機JVM

2024-09-06 09:37:45

WebApp類加載器Web 應用

2022-10-08 08:34:34

JVM加載機制代碼

2023-12-06 12:11:43

類加載器雙親委派模型

2021-09-24 08:10:40

Java 語言 Java 基礎
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 粉嫩高清一区二区三区 | 在线观看视频91 | 日韩久久中文字幕 | 亚洲一卡二卡 | 日韩精品久久久 | 国产农村妇女精品一二区 | 成年人在线视频 | 一区二区三区四区不卡视频 | 亚洲国产成人av好男人在线观看 | 黄色高清视频 | 久久精品99 | 成人免费在线观看 | 99久久国产| 成人精品鲁一区一区二区 | 国产成人黄色 | 久久久久久国产精品 | 欧美激情视频网站 | 一级黄色淫片 | 365夜爽爽欧美性午夜免费视频 | 久久av一区二区三区 | 99re6在线视频精品免费 | 国产一级一片免费播放 | 欧美午夜视频 | 久久久精品天堂 | 日韩精品一区二区三区在线观看 | 国产女人与拘做受免费视频 | 亚洲综合在线一区 | 欧美一级二级在线观看 | 精品亚洲一区二区三区 | 噜噜噜噜狠狠狠7777视频 | 欧美精品一区二区在线观看 | 国产精品视频一区二区三区不卡 | 丁香综合 | 一级一片在线观看 | 久久毛片 | 国产精品高潮呻吟久久av黑人 | 有码在线| 国产综合第一页 | 亚洲欧美一区二区三区国产精品 | 欧美久久久久久 | www亚洲精品 |