国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java中ClassLoader類加載學習總結

Java中ClassLoader類加載學習總結

2021-03-07 12:06Java教程網 Java教程

本篇文章主要給大家講述了Java中ClassLoader類加載的原理以及用法總結,一起學習下。

雙親委派模型

類加載這個概念應該算是Java語言的一種創新,目的是為了將類的加載過程與虛擬機解耦,達到”通過類的全限定名來獲取描述此類的二進制字節流“的目的。實現這個功能的代碼模塊就是類加載器。類加載器的基本模型就是大名鼎鼎的雙親委派模型(Parents Delegation Model)。聽上去很牛掰,其實邏輯很簡單,在需要加載一個類的時候,我們首先判斷該類是否已被加載,如果沒有就判斷是否已被父加載器加載,如果還沒有再調用自己的findClass方法嘗試加載。基本的模型就是這樣(盜圖侵刪):

Java中ClassLoader類加載學習總結

實現起來也很簡單,重點就是ClassLoader類的loadClass方法,源碼如下:

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
protected Class<?> loadClass(String name, boolean resolve)
  throws ClassNotFoundException
{
  synchronized (getClassLoadingLock(name)) {
    // First, check if the class has already been loaded
    Class<?> c = findLoadedClass(name);
    if (c == null) {
      long t0 = System.nanoTime();
      try {
        if (parent != null) {
          c = parent.loadClass(name, false);
        } else {
          c = findBootstrapClassOrNull(name);
        }
      } catch (ClassNotFoundException e) {
        // ClassNotFoundException thrown if class not found
        // from the non-null parent class loader
      }
      if (c == null) {
        // If still not found, then invoke findClass in order
        // to find the class.
        long t1 = System.nanoTime();
        c = findClass(name);
        // this is the defining class loader; record the stats
        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
        sun.misc.PerfCounter.getFindClasses().increment();
      }
    }
    if (resolve) {
      
      Class(c);
    }
    return c;
  }
}

突然感覺被逗了,怎么默認直接就拋了異常呢?其實是因為ClassLoader這個類是一個抽象類,實際在使用時候會寫個子類,這個方法會按照需要被重寫,來完成業務需要的加載過程。

自定義ClassLoader

在自定義ClassLoader的子類時候,我們常見的會有兩種做法,一種是重寫loadClass方法,另一種是重寫findClass方法。其實這兩種方法本質上差不多,畢竟loadClass也會調用findClass,但是從邏輯上講我們最好不要直接修改loadClass的內部邏輯。

個人認為比較好的做法其實是只在findClass里重寫自定義類的加載方法。

為啥說這種比較好呢,因為前面我也說道,loadClass這個方法是實現雙親委托模型邏輯的地方,擅自修改這個方法會導致模型被破壞,容易造成問題。因此我們最好是在雙親委托模型框架內進行小范圍的改動,不破壞原有的穩定結構。同時,也避免了自己重寫loadClass方法的過程中必須寫雙親委托的重復代碼,從代碼的復用性來看,不直接修改這個方法始終是比較好的選擇。

當然,如果是刻意要破壞雙親委托模型就另說。

破壞雙親委托模型

為什么要破壞雙親委托模型呢?

其實在某些情況下,我們可能需要加載兩個不同的類,但是不巧的是這兩個類的名字完全一樣,這時候雙親委托模型就無法滿足我們的要求了,我們就要重寫loadClass方法破壞雙親委托模型,讓同一個類名加載多次。當然,這里說的破壞只是局部意義上的破壞。

但是類名相同了,jvm怎么區別這兩個類呢?顯然,這并不會造成什么世界觀的崩塌,其實類在jvm里并不僅是通過類名來限定的,他還屬于加載他的ClassLoader。由不同ClassLoader加載的類其實是互不影響的。

做一個實驗。

我們先寫兩個類:

?
1
2
3
4
5
6
package com.mythsman.test;
public class Hello {
  public void say() {
    System.out.println("This is from Hello v1");
  }
}
?
1
2
3
4
5
6
package com.mythsman.test;
public class Hello {
  public void say() {
    System.out.println("This is from Hello v2");
  }
}

 

兩個類名字一樣,唯一的區別是方法的實現不一樣。我們先分別編譯,然后把生成的class文件重命名為Hello.class.1和Hello.class.2。

我們的目的是希望能在測試類里分別創建這兩個類的實例。

接著我們新建一個測試類com.mythsman.test.Main,在主函數里創建兩個自定義的ClassLoader:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ClassLoader classLoader1=new ClassLoader() {
  @Override
  public Class<?> loadClass(String s) throws ClassNotFoundException {
    try {
      if (s.equals("com.mythsman.test.Hello")) {
        byte[] classBytes = Files.readAllBytes(Paths.get("/home/myths/Desktop/test/Hello.class.1"));
        return defineClass(s, classBytes, 0, classBytes.length);
      }else{
        return super.loadClass(s);
      }
    }catch (IOException e) {
      throw new ClassNotFoundException(s);
    }
  }
};
ClassLoader classLoader2=new ClassLoader() {
  @Override
  public Class<?> loadClass(String s) throws ClassNotFoundException {
    try {
      if (s.equals("com.mythsman.test.Hello")) {
        byte[] classBytes = Files.readAllBytes(Paths.get("/home/myths/Desktop/test/Hello.class.2"));
        return defineClass(s, classBytes, 0, classBytes.length);
      }else{
        return super.loadClass(s);
      }
    }catch (IOException e) {
      throw new ClassNotFoundException(s);
    }
  }
};<br>

 

這兩個ClassLoader的用途就是分別關聯Hello類的兩種不同字節碼,我們需要讀取字節碼文件并通過defineClass方法加載成class。注意我們重載的是loadClass方法,如果是重載findClass方法那么由于loadClass方法的雙親委托處理機制,第二個ClassLoader的findClass方法其實并不會被調用。

那我們怎么生成實例呢?顯然我們不能直接用類名來引用(名稱沖突),那就只能用反射了:

?
1
2
3
4
Object helloV1=classLoader1.loadClass("com.mythsman.test.Hello").newInstance();
Object helloV2=classLoader2.loadClass("com.mythsman.test.Hello").newInstance();
helloV1.getClass().getMethod("say").invoke(helloV1);
helloV2.getClass().getMethod("say").invoke(helloV2);

 

輸出:

 

 

?
1
2
This is from Hello v1
This is from Hello v2

 

OK,這樣就算是完成了兩次加載,但是還有幾個注意點需要關注下。

兩個類的關系是什么

顯然這兩個類并不是同一個類,但是他們的名字一樣,那么類似isinstance of之類的操作符結果是什么樣的呢:

?
1
2
3
4
5
6
System.out.println("class:"+helloV1.getClass());
System.out.println("class:"+helloV2.getClass());
System.out.println("hashCode:"+helloV1.getClass().hashCode());
System.out.println("hashCode:"+helloV2.getClass().hashCode());
System.out.println("classLoader:"+helloV1.getClass().getClassLoader());
System.out.println("classLoader:"+helloV2.getClass().getClassLoader());

輸出:

 

 

?
1
2
3
4
5
6
class:class com.mythsman.test.Hello
class:class com.mythsman.test.Hello
hashCode:1581781576
hashCode:1725154839
classLoader:com.mythsman.test.Main$1@5e2de80c
classLoader:com.mythsman.test.Main$2@266474c2

 

他們的類名的確是一樣的,但是類的hashcode不一樣,也就意味著這兩個本質不是一個類,而且他們的類加載器也不同(其實就是Main的兩個內部類)。

這兩個類加載器跟系統的三層類加載器是什么關系

以第一個自定義的類加載器為例:

?
1
2
3
4
5
System.out.println(classLoader1.getParent().getParent().getParent());
System.out.println(classLoader1.getParent().getParent());
System.out.println(classLoader1.getParent());
System.out.println(classLoader1 );
System.out.println(ClassLoader.getSystemClassLoader());

 

輸出:

?
1
2
3
4
5
null
sun.misc.Launcher$ExtClassLoader@60e53b93
sun.misc.Launcher$AppClassLoader@18b4aac2
com.mythsman.test.Main$1@5e2de80c
sun.misc.Launcher$AppClassLoader@18b4aac2

 

 
我們可以看到,第四行就是這個自定義的ClassLoader,他的父親是AppClassLoader,爺爺是ExtClassLoader,太爺爺是null,其實就是用C寫的BootStrapClassLoader。而當前系統的ClassLoader就是這個AppClassLoader。

 

當然,這里說的父子關系并不是繼承關系,而是組合關系,子ClassLoader保存了父ClassLoader的一個引用(parent)。

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 日韩在线中文 | 特黄特色大片免费视频观看 | 久久精品成人 | 女人夜夜春高潮爽av片 | 91av在线电影 | 国产一区二区三区免费在线观看 | 91极品视频在线观看 | 日韩中文字幕一区二区三区 | 日韩操操操 | 欧美日韩在线看 | 免费一级黄色 | 精品亚洲永久免费精品 | www.久久精品| 欧洲精品| 懂色一区| 在线播放国产一区二区三区 | 国产乱视频 | 国产一区二区三区免费看 | 欧美日韩中文字幕 | 日韩高清av| 国产成人一区二区三区在线观看 | 欧美激情综合网 | 欧美成人精品一区二区男人看 | 人妖天堂狠狠ts人妖天堂狠狠 | 一级做a爰性色毛片免费1 | 国产精品亚洲一区二区三区在线 | 国内精品久久久久久影视8 有码在线 | 欧美成人a | 精品无码久久久久国产 | 中文字幕一区二区三区乱码图片 | 国产在线观看一区 | 欧美精品久久久 | 日韩高清在线一区 | 日韩免费在线观看视频 | 99久久婷婷国产综合精品草原 | 欧美日韩六区 | 欧美一级在线 | 天天操天天插 | 国产一级黄色大片 | 91精品国产高清久久久久久久久 | 日本中文字幕在线电影 |