真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

JVM的藝術(shù)之如何使用類加載器

這篇文章主要講解了“JVM的藝術(shù)之如何使用類加載器”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JVM的藝術(shù)之如何使用類加載器”吧!

成都創(chuàng)新互聯(lián)公司一直通過網(wǎng)站建設(shè)和網(wǎng)站營銷幫助企業(yè)獲得更多客戶資源。 以"深度挖掘,量身打造,注重實效"的一站式服務(wù),以網(wǎng)站設(shè)計制作、成都做網(wǎng)站、移動互聯(lián)產(chǎn)品、全網(wǎng)整合營銷推廣服務(wù)為核心業(yè)務(wù)。十余年網(wǎng)站制作的經(jīng)驗,使用新網(wǎng)站建設(shè)技術(shù),全新開發(fā)出的標(biāo)準(zhǔn)網(wǎng)站,不但價格便宜而且實用、靈活,特別適合中小公司網(wǎng)站制作。網(wǎng)站管理系統(tǒng)簡單易用,維護(hù)方便,您可以完全操作網(wǎng)站資料,是中小公司快速網(wǎng)站建設(shè)的選擇。

正式介紹線程的上下文類加載器之前需要介紹一些理論性的東東

當(dāng)前類加載器(Current ClassLoader):每一個類都會使用自己的類加載器(既加載自身的類加載器)來去加載其它類(指的是所依賴的類),如果ClassX引用了ClassY,那么ClassX的類加載器就會加載ClassY(前提是ClassY尚未被加載)。

線程上下文類加載器(Context ClassLoader):線程上下文類加載器是從JDK1.2開始引入的,類Thread中的**getContextClassLoader()setContextClassLoader(ClassLoader cl)**分別用來獲取和設(shè)置上下文類加載器。如果沒有通過setContextClassLoader(ClassLoader cl)進(jìn)行設(shè)置的話,線程將繼承其父線程的上下文類加載器。

Java應(yīng)用運(yùn)行時初始線程的上下文類加載器是系統(tǒng)類加載器 

為什么使用線程上下文類加載?

為什么使用線程上下文類加載?上篇文章我也簡單的提到了。線程上下文類加載的設(shè)計初衷,原因就在于我們JAVA語言的SPI機(jī)制,我又提供了一張圖,希望下面這張圖可以全面的闡述上下文類加載器的含義。JVM的藝術(shù)之如何使用類加載器 

線程上下文類加載器的重要性

我們在使用JDBC操作數(shù)據(jù)庫時會如下進(jìn)行編寫:

Class.forName("com.MySQL.driver.Driver");

Connection conn = Driver.getConnection();

Statement st = conn.getStatement();

JDBC是一個標(biāo)準(zhǔn),這就說明使用到的Connection和Statement都是內(nèi)置在JDK當(dāng)中的標(biāo)準(zhǔn),都是抽象接口,而且是位于rt.jar中,其實現(xiàn)肯定是由不同的數(shù)據(jù)庫廠商來實現(xiàn),那么問題就來了:這些標(biāo)準(zhǔn)都是由根類加載器所加載的,但是具體的實現(xiàn)是由具體的廠商來做的,那肯定是需要將廠商的jar放到工程的classpath當(dāng)中來進(jìn)行使用,很顯然廠商的這些類是沒辦法由啟動類加載器去加載,會由應(yīng)用類加載器去加載,而根據(jù)**“父類加載器所加載的類或接口是看不到子類加載器所加載的類或接口,而子類加載器所加載的類或接口是能夠看到父類加載器加載的類或接口的”這一原則,那么會導(dǎo)致這樣一個局面:比如說java.sql包下面的某個類會由啟動類加載器去加載,該類有可能會要訪問具體的實現(xiàn)類,但具體實現(xiàn)類是由應(yīng)用類加載器所加載的,java.sql類加載器是根據(jù)看不到具體實現(xiàn)類加載器所加載的類的,這就是基于雙親委托模型所出現(xiàn)的一個非常致命的問題,這種問題不僅是在JDBC中會出現(xiàn),在JNDI、xml解析等SPI(Service Provider Interface)**場景下都會出現(xiàn)的所以這里總結(jié)一下:父ClassLoader可以使用當(dāng)前線程Thread.currentThread().getContextLoader()所指定的ClassLoader加載的類,這就改變了父ClassLoader不能使用子ClassLoader或者其它沒有直接父子關(guān)系的ClassLoader加載的類的情況,既改變了雙親委托模型。線程上下文類加載器就是當(dāng)前線程的Current ClassLoader。在雙親委托模型下,類加載是由下至上的,既下層的類加載器會委托上層進(jìn)行加載。但是對于SPI來說,有些接口是Java核心庫所提供的,而Java核心庫是由啟動類加載器來加載的,而這些接口的實現(xiàn)卻來自于不同的jar包(廠商提供)。Java的啟動類加載器是不會加載其它來源的jar包,這樣傳統(tǒng)的雙親委托模型就無法滿足SPI的要求。而通過給當(dāng)前線程設(shè)置上下文類加載器,就可以由設(shè)置的上下文類加載器來實現(xiàn)對于接口實現(xiàn)類的加載。 

下面以JDBC的這種SPI場景用圖來更具體的描述一下:
JVM的藝術(shù)之如何使用類加載器  

很明顯JDBC會去引用JDBCImpl的具體廠商的實現(xiàn),而JDBC標(biāo)準(zhǔn)是由根類加載器所加載,那對于具體實現(xiàn)廠商的類也會用根類加載器去加載,而由于它們是處于工程中的classPath當(dāng)中,由系統(tǒng)類加載器去加載,很顯然是沒辦法由根類加載器去加載的,為了解決這個問題,線程的上下文類加載器就發(fā)揮作用了。

分析:由上面的理論可知:Java應(yīng)用運(yùn)行時初始線程的上下文類加載器是系統(tǒng)類加載器 

那思考一下:為什么默認(rèn)的線程上下文類加載器就是系統(tǒng)類加載器呢?肯定是在某個地方給設(shè)置了,其實它是在Launcher中進(jìn)行設(shè)置的,如下:
JVM的藝術(shù)之如何使用類加載器     
1、線程上下文類加載器的一般使用模式(獲取 - 使用 - 還原)
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();//獲取
        try{
            ClassLoader targetTccl = xxx;//要設(shè)置的上下文類記載器
            Thread.currentThread().setContextClassLoader(targetTccl);//設(shè)置
            myMethod();//使用
        } finally {
            Thread.currentThread().setContextClassLoader(classLoader);//還原
        }
   
2、如果一個類由類加載器A加載,那么這個類的依賴類也是由相同的類加載器加載的(如果該依賴類之前沒有被加載過的話),ContextClassLoader的作用就是為破壞Java的類加載委托機(jī)制。 
3、當(dāng)高層提供了統(tǒng)一的接口讓低層來實現(xiàn),同時又要在高層加載(或?qū)嵗┑蛯拥念悤r,就必須要通過線程上下文類加載器來幫助高層的ClassLoader找到并加載該類。
Thread.currentThread().getContextClassLoader();//獲取

Thread.currentThread().setContextClassLoader(targetTccl);//設(shè)置
 

至此線程上下文類加載器就介紹到這里。 

類加載的過程

其實一個類從加載到使用是要經(jīng)歷很多個過程的,下面我們來詳細(xì)的說說,一個類從加載到初始化的這個過程,然而還有哪些坑不為人知。

下面給出一張圖:

JVM的藝術(shù)之如何使用類加載器  

固定的類加載執(zhí)行順序: 加載  驗證  準(zhǔn)備 初始化 卸載 的執(zhí)行順序是一定的  為什么解析過程沒有在這個執(zhí)行順序中?(接下來分析)

什么時候觸發(fā)類加載不一定,但是類的初始化如下四種情況就要求一定初始化。 但是初始化之前 就一定會執(zhí)行 加載 驗證 準(zhǔn)備 三個階段。

觸發(fā)類加載的過程(由初始化過程引起的類加載)

1):使用new 關(guān)鍵字   獲取一個靜態(tài)屬性 設(shè)置一個靜態(tài)屬性   調(diào)用一個靜態(tài)方法。

int myValue = SuperClass.value;會導(dǎo)致父類初始化,但是不會導(dǎo)致子類初始化

SuperClass.Value = 3 ; 會導(dǎo)致父類初始化,不會導(dǎo)致子類初始化。

SubClass.staticMethod(); 先初始化父類 在初始化子類

SubClass sc = new SubClass(); 先初始化父類 再初始化子類

2):使用反射的時候,若發(fā)現(xiàn)類還沒有初始化,就會進(jìn)行初始化

Class clazz = Class.forName("com.hnnd.classloader.SubClass");

3):在初始化一個類的時,若發(fā)現(xiàn)其父類沒有初始化,就會先初始化父類

SubClass.staticMethod(); 先初始化父類 在初始化子類

4):啟動虛擬機(jī)的時候,需要加載包含main方法的類.

JVM的藝術(shù)之如何使用類加載器  
 class SuperClass{
     public static int value = 5;
     
     static {
      
      System.out.println("Superclass ...... init........");
     }
    }
    
    class SubClass extends SuperClass {
     
     static {
      System.out.println("subClass********************init");
     }
     
     public static void staticMethod(){
      System.out.println("superclass value"+SubClass.value);
     }
    }
 

下面我們對類的加載、連接、初始化這幾個過程逐一的解釋:

1:加載

1.1)根據(jù)全類名獲取到對應(yīng)類的字節(jié)碼流(字節(jié)流的來源 class 文件,網(wǎng)絡(luò)文件,還有反射的Proxygeneraotor.generaotorProxyClass)

1.2)把字節(jié)流中的靜態(tài)數(shù)據(jù)結(jié)構(gòu)加載到方法區(qū)中的運(yùn)行時數(shù)據(jù)結(jié)構(gòu)

1.3)在內(nèi)存中生成java.lang.Class對象,可以通過該對象來操作方法區(qū)中的數(shù)據(jù)結(jié)構(gòu)(通過反射)

2:驗證

文件格式的驗證: 驗證class文件開頭的0XCAFFBASE 開頭

驗證主次版本號是否在當(dāng)前的虛擬機(jī)的范圍之類

檢測jvm不支持的常量類型

元數(shù)據(jù)的校驗:

驗證本類是否有父類

驗證是否繼承了不允許繼承的類(final)修飾的類

驗證本類不是抽象類的時候,是否實現(xiàn)了所有的接口和父類的接口

**字節(jié)碼驗證:**驗證跳轉(zhuǎn)指令跳轉(zhuǎn)到 方法以外的指令.

驗證類型轉(zhuǎn)換是否為有效的, 比如子類對象賦值父類的引用是可以的,但是把父類對象賦值給子類引用是危險的

總而言之:字節(jié)碼驗證通過,并不能說明該字節(jié)碼一定沒有問題,但是字節(jié)碼驗證不通過。那么該字節(jié)碼文件一定是有問題:。

符號引用的驗證(發(fā)生在解析的過程中):

通過字符串描述的全類名是否能找到對應(yīng)的類。

指定類中是否包含字段描述符,以及簡單的字段和方法名稱。

3:準(zhǔn)備:為類變量分配內(nèi)存以及設(shè)置初始值。

比如public static int value = 123;

在準(zhǔn)備的過程中 value=0 而不是123  ,當(dāng)執(zhí)行類的初始化的方法的時候,value=123

若是一個靜態(tài)常量

public static final int value = 9; 那么在準(zhǔn)備的過程中value為9.

4:解析 :把符號引用替換成直接引用

符號引用分類:

CONSTANT_Class_info 類或者接口的符號引用

CONSTANT_Fieldref_info 字段的符號引用

CONSTANT_Methodref_info 方法的符號引用

CONSTANT_intfaceMethodref_info-   接口中方法的符號引用

CONSTANT_NameAndType_info  子類或者方法的符號引用.

CONSTANT_MethodHandle_Info 方法句柄

CONSTANT_InvokeDynamic_Info 動態(tài)調(diào)用

直接引用:

指向?qū)ο蟮闹羔?/p>

相對偏移量

操作句柄

5:初始化:類的初始化時類加載的最后一步:執(zhí)行類的構(gòu)造器,為所有的類變量進(jìn)行賦值(編譯器生成CLInit<>)

類構(gòu)造器是什么?:類構(gòu)造器是編譯器按照J(rèn)ava源文件總類變量和靜態(tài)代碼塊出現(xiàn)的順序來決定

靜態(tài)語句只能訪問定義在靜態(tài)語句之前的類變量,在其后的靜態(tài)變量能賦值 但是不能訪問。

父類中的靜態(tài)代碼塊優(yōu)先于子類靜態(tài)代碼塊執(zhí)行。

若類中沒有靜態(tài)代碼塊也沒有靜態(tài)類變量的話,那么編譯器就不會生成 Clint<>類構(gòu)造器的方法。

public class TestClassInit {
 public static void main(String[] args) {
  System.out.println(SubClass.sub_before_v);
 }
}

class SubClass extends SuperClass{
 public static int sub_before_v = 5;
 static {
  sub_before_v = 10;
  System.out.println("subclass init.......");
  sub_after_v=0;
  //報錯,static代碼塊中的代碼只能賦值后面的類變量 但是不能訪問。
  sub_before_v = sub_after_v;
 }
 public static int sub_after_v = 10;
}

class SuperClass {
 public static int super_before_v = 5;
 static{
  System.out.println("superclass init......");
 }
 public static int super_after_v = 10;
}

下面我們通過一系列的案例來說驗證上面所說的。先做個小的總結(jié)。

類的初始化需要對類進(jìn)行主動使用,下面總結(jié)了幾點(diǎn),都可以看做是對類的主動使用:

1:創(chuàng)建類的實例。

2:訪問某個類或者接口中的靜態(tài)變量,或者對其賦值。

3:訪問某個類的靜態(tài)方法。

4:反射。

5:初始化一個類的子類。

6:包含main方法的類。

7:jdk1.7開始提供動態(tài)語言的支持。

除了以上7種情況,都是被動使用,都不會導(dǎo)致類被初始化。

根據(jù)以上結(jié)論,我們來寫幾個案例,針對每種情況進(jìn)行一下證明。 

結(jié)論一:

靜態(tài)常量初始化過程是,在jvm連接之后,靜態(tài)常量的初始化,是由調(diào)用這個靜態(tài)常量方法所在的類的常量池中被保存,此時,被調(diào)用的靜態(tài)常量所在的類的class文件就可以被刪除,即使被刪除,該常量依然有效。調(diào)用某個類的靜態(tài)常量不能初始化該類。

代碼:

package com.jdyun.jvm001;

public class TestClass03 {

    public static void main(String[] args) {

        System.out.println(Pet1.a);
    }
}

class Pet1{

    public static final int a = 10;

    static {
        System.out.println("我是Pet1,我被初始化了");
    }
}

運(yùn)行結(jié)果:
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=64451:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath G:\jdyun-jvm\out\production\jdyun-jvm com.jdyun.jvm001.TestClass03
10

Process finished with exit code 0
 

從上面這個案例可知,一個類調(diào)用另一個類的常量不會導(dǎo)致一個類的初始化。 

結(jié)論二:
  • 此處聲明的靜態(tài)常量,按照之前的理解是靜態(tài)常量被調(diào)用不會初始化該靜態(tài)常量所在的類
  • 但是此處當(dāng)靜態(tài)常量的值是一個引用類型的時候,這個時候該靜態(tài)常量所在的類就會被初始化
  • 故此會先打印我被初始化了,然后在打印a的隨機(jī)值

代碼:

package com.jdyun.jvm001;

import java.util.UUID;

public class TestClass03 {

    public static void main(String[] args) {
        System.out.println(Pet1.a);

    }
}

class Pet1{
    public static final String a = UUID.randomUUID().toString();

    static{
        System.out.println("我被初始化了");
    }
}

運(yùn)行結(jié)果:
    
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=50237:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath G:\jdyun-jvm\out\production\jdyun-jvm com.jdyun.jvm001.TestClass03
    
我被初始化了
e5b56749-5a97-405f-9fe9-dfe4211bc0ce

Process finished with exit code 0
   
結(jié)論三:

靜態(tài)變量初始化與靜態(tài)常量初始化不同,靜態(tài)變量初始化是在初始化階段被賦予真實的值比如int a = 2,那么2會被真正的賦值給a。

如果某個類調(diào)用了該類的靜態(tài)變量,那么靜態(tài)變量所在的類就會被視為被主動調(diào)用了。那么該類就會被初始化。

該類如果有靜態(tài)代碼塊兒那么靜態(tài)代碼塊兒的優(yōu)先級高于靜態(tài)變量。

如果該靜態(tài)變量所在的類中有父類,那么會優(yōu)先初始化父類。

package com.jdyun.jvm001;

import java.util.Random;
import java.util.UUID;

public class TestClass03 {

    public static void main(String[] args) {

        System.out.println(Dog3.a);

    }
}

class Dog3 extends Pet1{

    public static final  int a = new Random().nextInt();

    static {
        System.out.println("我是Pet1,我是父類,我被最先加載了");
    }

}

class Pet1{

    static{
        System.out.println("我被初始化了");
    }
}

運(yùn)行結(jié)果:
    
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=64951:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath G:\jdyun-jvm\out\production\jdyun-jvm com.jdyun.jvm001.TestClass03
                    
我被初始化了
我是Pet1,我是父類,我被最先加載了
-1203457101

Process finished with exit code 0
    
結(jié)論四:

驗證初始化次數(shù),只會被初始化一次。

package com.jdyun.jvm001;


import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;

public class MyTest02  extends  ClassLoader{

    public static void main(String[] args) throws ClassNotFoundException {
        //1,驗證初始化次數(shù)
        for(int i=0;i<50;i++){
            Test01 test01 = new Test01();
        }

    }
}

class Test01{

    static{
        System.out.println("我被初始化了");
    }
}

運(yùn)行結(jié)果:
    
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=65340:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath G:\jdyun-jvm\out\production\jdyun-jvm com.jdyun.jvm001.MyTest02
我被初始化了

Process finished with exit code 0
   
結(jié)論五:

接口的初始化,子接口的初始化不會導(dǎo)致父接口的初始化,如果可以導(dǎo)致父接口的初始化,那么Test01類中的靜態(tài)代碼塊兒就會被打印。很顯然結(jié)果來看,Test01

中的靜態(tài)代碼塊兒沒有被打印,所以,接口的初始化中,子接口的初始化,不會導(dǎo)致父接口的初始化。

package com.jdyun.jvm001;


import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;

public class MyTest02  extends  ClassLoader{

    public static void main(String[] args) throws ClassNotFoundException {

        //2,接口初始化,子接口的初始化不會導(dǎo)致父接口的初始化
        System.out.println(MyChild.b);
       /* System.out.println(MyParent.test01);
        System.out.println(MyChild.test001);*/

        //3,反射初始化類
        //Class.forName("com.jdyun.jvm001.Test01");

        //4,創(chuàng)建數(shù)組不會導(dǎo)致類的初始化
        //Test01[] test01 = new Test01[1];

        //5,靜態(tài)變量賦值
        //System.out.println(MyChild.b);

        //Class clesses = String.class;


    }
}

class Test01{

    static{
        System.out.println("Test01被初始化了");
    }
}

interface MyParent{

    Test01 test01 = new Test01();

    public static final String a="5";

}

interface MyChild extends MyParent {

    public static  Integer b= UUID.randomUUID().hashCode();


}
"C:\Program  Files\Java\jdk-11.0. 2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=49632:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath G:\jdyun-jvm\out\production\jdyun-jvm com.jdyun.jvm001.MyTest02
-221561202

Process finished with exit code 0
   
結(jié)論六:

創(chuàng)建一個數(shù)組,不會導(dǎo)致類的初始化。

package com.jdyun.jvm001;


import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;

public class MyTest02  extends  ClassLoader{

    public static void main(String[] args) throws ClassNotFoundException {

        //4,創(chuàng)建數(shù)組不會導(dǎo)致類的初始化
        Test01[] test01 = new Test01[1];
    }
}

class Test01{

    static{
        System.out.println("Test01被初始化了");
    }
}

運(yùn)行結(jié)果:

"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=50058:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath G:\jdyun-jvm\out\production\jdyun-jvm com.jdyun.jvm001.MyTest02

Process finished with exit code 0
  
結(jié)論七:

此處聲明的靜態(tài)常量,按照之前的理解是靜態(tài)常量被調(diào)用不會初始化該靜態(tài)常量所在的類 但是此處當(dāng)靜態(tài)常量的值是一個引用類型的時候,這個時候該靜態(tài)常量所在的類就會被初始化 故此會先打印我被初始化了,然后在打印a的隨機(jī)值

package com.jdyun.jvm07;

import java.util.Random;
import java.util.UUID;

/**
 * 此處聲明的靜態(tài)常量,按照之前的理解是靜態(tài)常量被調(diào)用不會初始化該靜態(tài)常量所在的類
 * 但是此處當(dāng)靜態(tài)常量的值是一個引用類型的時候,這個時候該靜態(tài)常量所在的類就會被初始化
 * 故此會先打印我被初始化了,然后在打印a的隨機(jī)值
 */
public class Test  {

    public static void main(String[] args) {

        System.out.println(Pet.a);

    }
}

class Pet{

    public static final String a = UUID.randomUUID().toString();

    static{

        System.out.println("我被初始化了");
    }
}
運(yùn)行結(jié)果:
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=50995:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath G:\jdyun-jvm\out\production\jdyun-jvm com.jdyun.jvm07.Test
我被初始化了
3febaad7-90fe-4d7f-be1c-62b70b9f41cc

Process finished with exit code 0
   
結(jié)論八:

對子接口靜態(tài)常量調(diào)用時,父接口沒有被加載也并沒有被初始化。當(dāng)我們有兩個接口,父子接口,然后在子接口中聲明一個靜態(tài)變量,此時對子接口中的靜態(tài)變量進(jìn)行主動調(diào)用,此時父接口沒有被初始化,也沒有被加載。(刪除父接口中的class)

package com.jdyun.jvm8;

import java.util.Random;

public class Test {

    public static void main(String[] args) {
        System.out.println(MyChild.b);
    }

}

interface MyParent{

    public static final String a="5";

}

interface MyChild extends MyParent{

    public static  Integer b= 1;
}

運(yùn)行結(jié)果:
    
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=51297:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath G:\jdyun-jvm\out\production\jdyun-jvm com.jdyun.jvm8.Test
1

Process finished with exit code 0
   
結(jié)論九:

接口中的變量賦予引用初始值會初始化子接口。

public class Test {

    public static void main(String[] args) {
        System.out.println(MyChild.b);
    }

}

interface MyParent{

    public static String a=5;

}

interface MyChild extends  MyParent{

    Integer b= new Random().nextInt(2);
}

感謝各位的閱讀,以上就是“JVM的藝術(shù)之如何使用類加載器”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對JVM的藝術(shù)之如何使用類加載器這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!


名稱欄目:JVM的藝術(shù)之如何使用類加載器
網(wǎng)頁路徑:http://weahome.cn/article/jsichd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部