最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Java自定義類加載器及JVM自帶的類加載器之間的交互關(guān)系

 更新時(shí)間:2021年02月22日 08:39:33   作者:小蘿莉_Lolita  
這篇文章主要介紹了淺談Java自定義類加載器及JVM自帶的類加載器之間的交互關(guān)系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧

JVM自帶的類加載器:

其關(guān)系如下:

其中,類加載器在加載類的時(shí)候是使用了所謂的“父委托”機(jī)制。其中,除了根類加載器以外,其他的類加載器都有且只有一個(gè)父類加載器。

關(guān)于父委托機(jī)制的說明:

當(dāng)生成 一個(gè)自定義的類加載器實(shí)例時(shí),如果沒有指定它的父加載器,那么系統(tǒng)類加載器將成為該類加載器的父類加載器

下面,自定義類加載器。自定義的類加載器必須繼承java.lang.ClassLoader類

import java.io.*;
public class MyClassLoader extends ClassLoader {
  private String name;  //類加載器的名字
  private String path;  //加載類的路徑
  private final String fileType = ".class"; //class文件的擴(kuò)展名
  public MyClassLoader(String name){
    super(); //讓系統(tǒng)類加載器成為該類加載器的父 類加載器,該句可省略不寫
    this.name = name;
  }
  public MyClassLoader(ClassLoader parent,String name){
    super(parent); //顯示指定該類加載器的父 類加載器
    this.name = name;
  }
  @Override
  public String toString() {
    return this.name;
  }
  public String getPath() {
    return path;
  }
  public void setPath(String path) {
    this.path = path;
  }
  //實(shí)現(xiàn)自定義的類加載器必須重寫findClass方法,否則ClassLoader類中的findClass()方法是拋出了異常
  @Override
  public Class findClass(String name)throws ClassNotFoundException{
    byte[] data = this.loadClassData(name);
    return this.defineClass(name,data,0,data.length);
  }
  private byte[] loadClassData(String name){
    InputStream is = null;
    byte[] data = null;
    ByteArrayOutputStream baos = null;
    try {
      this.name = this.name.replace(".","\\"); //com.dream.it---->com\dream\it
      is = new FileInputStream(new File(path + name + fileType));
      int ch;
      while(-1 != (ch = is.read())){
        baos.write(ch);  //將數(shù)據(jù)寫入到字節(jié)數(shù)組輸出流對(duì)象中去
      }
      data = baos.toByteArray();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      try {
        is.close();
        baos.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return data;
  }
  public static void main(String[] args) throws Exception {
    MyClassLoader loader1 = new MyClassLoader("loader1");
    loader1.setPath("d:/myapp/serverlib/");
    MyClassLoader loader2 = new MyClassLoader(loader1,"loader2"); //loader1作為loader2的父 類加載器
    loader2.setPath("d:/myapp/clientlib");
    MyClassLoader loader3 = new MyClassLoader(null,"loader3");//父類加載器為null,表明其父類加載器為根類加載器
    loader3.setPath("d:/myapp/otherlib");
    test(loader2);
    test(loader3);
  }
  public static void test(ClassLoader cl) throws Exception {
    Class clazz = cl.loadClass("Sample");
    Object object = clazz.newInstance();
  }
}

附上findClass()方法的JDK說明

protected Class<?> findClass(String name) throws ClassNotFoundException
Finds the class with the specified binary name. 
This method should be overridden by class loader
implementations that follow the delegation model 
for loading classes, and will be invoked by the 
loadClass method after checking the parent class
loader for the requested class. The default 
implementation throws a ClassNotFoundException. 

大致說明一下意思:通過指定的name來查找類。該方法應(yīng)該被類加載器的實(shí)現(xiàn)類重寫,從而能夠保證在加載類的時(shí)候可以遵循委托機(jī)制模型。在loadClass()方法(該方法是由JVM調(diào)用的)中,檢查其父類加載器之后,該方法再被調(diào)用去加載請(qǐng)求的類。默認(rèn)該方法的實(shí)現(xiàn)是拋出了一個(gè)ClassNotFoundException異常。

其實(shí),所謂的加載類,無非就是讀取.class文件到內(nèi)存中,所以在findClass()方法中,loadClassData()方法用于讀取.class文件的數(shù)據(jù),并返回一個(gè)字節(jié)數(shù)組。然后利用ClassLoader類的defineClass()方法將字節(jié)數(shù)組轉(zhuǎn)換為Class對(duì)象。

上述自定義的類加載器loader1,loader2,loader3及JVM自帶的類加載器之間的關(guān)系如下:

對(duì)于各個(gè)類加載器,系統(tǒng)的類加載器是從環(huán)境變量classpath中讀取.class文件實(shí)現(xiàn)類的加載;loader1是從目錄d:/myapp/serverlib/下讀取.class文件;loader2是從目錄d:/myapp/clientlib/下讀取.class文件,loader3是從目錄d:/myapp/otherlib/下讀取.class文件

執(zhí)行結(jié)果:

此處我們分析一下出現(xiàn)這種執(zhí)行結(jié)果的原因:

當(dāng)執(zhí)行l(wèi)oader2.loadClass(“Sample”)時(shí)先由它上層的所有父類加載器嘗試加載Sample類。

loader1從D:\myapp\serverliv目錄下成功加載了Sample類,所以loader1是Sample類的定義類加載器,loader1和loader2是Sample類的初始類加載器。

當(dāng)執(zhí)行l(wèi)oader3.loadClass(“Sample”)時(shí),先由它上層的所有父類加載器嘗試加載Sample類。

loader3的父加載器為根類加載器,它無法加載Sample類,接著loader3從D:\myapp\otherlib目錄下成功加載Sample類,所以loader3是Sample類的定義類加載器及初始類加載器。

在Sample類中主動(dòng)使用了Dog類(new Dog()),當(dāng)執(zhí)行Sample類的構(gòu)造方法中的new Dog()語句時(shí),JVM需要先加載Dog類,到底用哪個(gè)類加載器家在呢?

從上述的打印結(jié)果中可以看出,加載Sample類的loader1還加載了Dog類,JVM會(huì)用Sample類的定義類加載器去加載Dog類,加載過程中也同樣采用了父親委托機(jī)制。

為了驗(yàn)證這一點(diǎn),可以吧D:\myapp\serverlib目錄下Dog.class文件刪除,然后在D:\myapp\syslib目錄下存放一個(gè)Dog.class文件,此時(shí)打印結(jié)果如下:

Sample:loader1
Dog:sun.misc.Launcher$AppClassLoader@1b84c92
Sample:loader3
Dog:loader3

由此可見,當(dāng)由loader1加載的Sample類首次主動(dòng)使用Dog類時(shí),Dog類由系統(tǒng)類加載器加載,如果把D:\myapp\serverlib和D:\myapp\syslib目錄下的Dog.class文件都刪除,然后在D:\myapp\client目錄下存放一個(gè)Dog.class文件。

此時(shí)文件結(jié)構(gòu)如下圖所示:

當(dāng)Loader1加載Sample類首次主動(dòng)使用Dog類時(shí),由于loader1及其父類加載器都無法加載Dog類,因此test(loader2)會(huì)拋出ClassNotFoundExcption.

這又是因?yàn)槭裁丛蚰兀?/p>

這又牽扯到命名空間的問題。

同一個(gè)命名空間內(nèi)的類時(shí)相互可見的。

子加載器的命名空間包含所有父類加載器的命名空間,因此由子加載器加載的類能看見父類加載器加載的類。例如系統(tǒng)類加載器加載的類能看見根類加載器加載的類。由父加載器加載的類不能看見子加載器加載的類。

如果兩個(gè)加載器之間沒有直接或間接的父子關(guān)系,那么它們各自加載的類相互不可見。

對(duì)于上述問題,loader1可以加載Sample類,而Dog類只能由loader2加載Dog類,loader1是Loader2的父類加載器,父加載器loader1加載的類Sample不能看見子加載器loader2加載的類Dog,所以會(huì)拋出異常。

對(duì)于上述實(shí)例中的main方法,我們不調(diào)用test方法,換成如下代碼

Class clazz = loader1.loadClass("Sample");
Object obj = clazz.newInstance();
Sample sample = (Sample)obj;
System.out.println(sample.v1);

MyClassLoader類由系統(tǒng)類加載器加載,而Sample類由loader1類加載器加載,所以MyClassLoader類看不見Sample類。在MyClassLoader類的main方法中使用Sample類,會(huì)導(dǎo)致NoClassFoundError錯(cuò)誤。

當(dāng)兩個(gè)不同命名空間內(nèi)的類相互不可見時(shí),可采用Java反射機(jī)制來訪問對(duì)象實(shí)例的屬性和方法。

將上述代碼修改:

Class clazz = loader1.loadClass("Sample");
Object obj = clazz.newInstance();
Field field = clazz.getField("v1");
int v1 = field.getInt(obj);
System.out.println(v1);

此時(shí),可以獲取到對(duì)象中的v1屬性值。利用反射機(jī)制,我們可以跨越這種命名空間的限制。

補(bǔ)充:

命名空間:

運(yùn)行時(shí)包:

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • 一篇文章解決Java異常處理

    一篇文章解決Java異常處理

    這篇文章主要給大家介紹了關(guān)于如何通過一篇文章解決Java異常處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 運(yùn)行java的class文件方法詳解

    運(yùn)行java的class文件方法詳解

    這篇文章主要詳細(xì)介紹了運(yùn)行java的class文件方法的相關(guān)資料,需要的朋友可以參考下
    2015-02-02
  • Java BigDecimal使用方法詳解

    Java BigDecimal使用方法詳解

    Java在java.math包中提供的API類BigDecimal,用來對(duì)超過16位有效位的數(shù)進(jìn)行精確的運(yùn)算。雙精度浮點(diǎn)型變量double可以處理16位有效數(shù),但在實(shí)際應(yīng)用中,可能需要對(duì)更大或者更小的數(shù)進(jìn)行運(yùn)算和處理
    2022-12-12
  • 批量上傳Jar包到Maven私服的工具的方法

    批量上傳Jar包到Maven私服的工具的方法

    這篇文章主要介紹了批量上傳Jar包到Maven私服的工具的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12
  • Java持久層框架Mybatis入門詳細(xì)教程

    Java持久層框架Mybatis入門詳細(xì)教程

    Mybatis持久層框架支持自定義SQL、存儲(chǔ)過程以及高級(jí)映射,可以通過XML或注解來配置和映射原始類型、接口和Java POJOs為數(shù)據(jù)庫(kù)中的記錄,接下來通過本文給大家介紹Java持久層框架Mybatis入門詳細(xì)教程,一起學(xué)習(xí)下吧
    2021-06-06
  • servlet之session簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    servlet之session簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了servlet之session簡(jiǎn)介,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • 一文詳解如何在Java?Maven項(xiàng)目中使用JUnit?5進(jìn)行測(cè)試

    一文詳解如何在Java?Maven項(xiàng)目中使用JUnit?5進(jìn)行測(cè)試

    這篇文章主要介紹了如何在Java?Maven項(xiàng)目中使用JUnit?5進(jìn)行測(cè)試的相關(guān)資料,JUnit5是一個(gè)流行的Java測(cè)試框架,它涵蓋了JUnit5的概述、環(huán)境配置、編寫測(cè)試用例、運(yùn)行測(cè)試、高級(jí)特性和最佳實(shí)踐,需要的朋友可以參考下
    2025-04-04
  • MyBatis如何使用(一)

    MyBatis如何使用(一)

    這篇文章主要介紹了MyBatis如何使用(一)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-07-07
  • SpringBoot?2.x整合Log4j2日志的詳細(xì)步驟

    SpringBoot?2.x整合Log4j2日志的詳細(xì)步驟

    log4j2優(yōu)越的性能其原因在于log4j2使用了LMAX,一個(gè)無鎖的線程間通信庫(kù)代替了,logback和log4j之前的隊(duì)列,并發(fā)性能大大提升,下面這篇文章主要給大家介紹了關(guān)于SpringBoot?2.x整合Log4j2日志的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • 如何對(duì)quartz定時(shí)任務(wù)設(shè)置結(jié)束時(shí)間

    如何對(duì)quartz定時(shí)任務(wù)設(shè)置結(jié)束時(shí)間

    這篇文章主要介紹了如何對(duì)quartz定時(shí)任務(wù)設(shè)置結(jié)束時(shí)間問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12

最新評(píng)論

都江堰市| 化州市| 枣强县| 巨鹿县| 伊川县| 太和县| 柯坪县| 淳化县| 闽清县| 汾西县| 桂林市| 绥宁县| 旌德县| 融水| 中方县| 卢龙县| 泰和县| 墨玉县| 雅安市| 静海县| 贵德县| 肥东县| 平果县| 和田市| 余江县| 丁青县| 蚌埠市| 台湾省| 尖扎县| 鄯善县| 慈溪市| 逊克县| 温州市| 铜梁县| 洪江市| 明光市| 定陶县| 平泉县| 隆安县| 中西区| 永福县|