亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》
  • 首頁 > 
  • 教程 > 
  • 開發技術 > 
  • Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

發布時間:2021-02-22 15:47:29 來源:億速云 閱讀:190 作者:清風 欄目:開發技術

這篇“Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么”文章,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要參考一下,對于“Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么”,小編整理了以下知識點,請大家跟著小編的步伐一步一步的慢慢理解,接下來就讓我們進入主題吧。

Java可以用來干什么

Java主要應用于:1. web開發;2. Android開發;3. 客戶端開發;4. 網頁開發;5. 企業級應用開發;6. Java大數據開發;7.游戲開發等。

JVM自帶的類加載器:

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

其關系如下:

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

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

關于父委托機制的說明:

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

當生成 一個自定義的類加載器實例時,如果沒有指定它的父加載器,那么系統類加載器將成為該類加載器的父類加載器

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

import java.io.*;
public class MyClassLoader extends ClassLoader {
  private String name;  //類加載器的名字
  private String path;  //加載類的路徑
  private final String fileType = ".class"; //class文件的擴展名
  public MyClassLoader(String name){
    super(); //讓系統類加載器成為該類加載器的父 類加載器,該句可省略不寫
    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;
  }
  //實現自定義的類加載器必須重寫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);  //將數據寫入到字節數組輸出流對象中去
      }
      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來查找類。該方法應該被類加載器的實現類重寫,從而能夠保證在加載類的時候可以遵循委托機制模型。在loadClass()方法(該方法是由JVM調用的)中,檢查其父類加載器之后,該方法再被調用去加載請求的類。默認該方法的實現是拋出了一個ClassNotFoundException異常。

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

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

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

對于各個類加載器,系統的類加載器是從環境變量classpath中讀取.class文件實現類的加載;loader1是從目錄d:/myapp/serverlib/下讀取.class文件;loader2是從目錄d:/myapp/clientlib/下讀取.class文件,loader3是從目錄d:/myapp/otherlib/下讀取.class文件

執行結果:

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

此處我們分析一下出現這種執行結果的原因:

當執行loader2.loadClass(“Sample”)時先由它上層的所有父類加載器嘗試加載Sample類。

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

當執行loader3.loadClass(“Sample”)時,先由它上層的所有父類加載器嘗試加載Sample類。

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

在Sample類中主動使用了Dog類(new Dog()),當執行Sample類的構造方法中的new Dog()語句時,JVM需要先加載Dog類,到底用哪個類加載器家在呢?

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

為了驗證這一點,可以吧D:\myapp\serverlib目錄下Dog.class文件刪除,然后在D:\myapp\syslib目錄下存放一個Dog.class文件,此時打印結果如下:

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

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

此時文件結構如下圖所示:

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

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

這又是因為什么原因呢?

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

同一個命名空間內的類時相互可見的。

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

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

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

對于上述實例中的main方法,我們不調用test方法,換成如下代碼

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

MyClassLoader類由系統類加載器加載,而Sample類由loader1類加載器加載,所以MyClassLoader類看不見Sample類。在MyClassLoader類的main方法中使用Sample類,會導致NoClassFoundError錯誤。

當兩個不同命名空間內的類相互不可見時,可采用Java反射機制來訪問對象實例的屬性和方法。

將上述代碼修改:

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

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

補充:

命名空間:

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

運行時包:

Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么

以上是“Java自定義類加載器及JVM自帶的類加載器之間的交互關系是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

隆尧县| 汪清县| 缙云县| 屏东县| 沈阳市| 五原县| 南投县| 昭苏县| 泸溪县| 延吉市| 勃利县| 松桃| 济阳县| 根河市| 惠来县| 顺昌县| 屏东市| 商都县| 华安县| 西林县| 博客| 张家口市| 德安县| 武城县| 禹城市| 旌德县| 黄冈市| 阳春市| 叙永县| 庆云县| 瑞安市| 新绛县| 清徐县| 枝江市| 乐平市| 镇安县| 西充县| 常熟市| 台北县| 长岭县| 修文县|