面試刷題23:類加載過程和雙親委派機制?

面試刷題23:類加載過程和雙親委派機制?


jvm賦能java跨平臺的能力,而類加載機制是深入理解java的必要條件。


我是李福春,我在準備面試,今天的問題是:


java的類加載機制是怎樣的?什麼是雙親委派原則?


答:java的類加載過程分為 加載,鏈接,初始化。
加載:即從數據源(jar,class,網絡)加載class文件到jvm,映射為class對象,如果不是classFile結構,拋出ClassFormatError;
鏈接:把第一步得到的class對象轉換到jvm環境,進行驗證(字節信息是否符合jvm規範,否則拋出VerifyError),準備(為靜態變量分配內存空間),解析(常量池中的符號引用替換為直接引用);
初始化:即為靜態變量和靜態代碼塊賦值。


java的類加載器部分的加載器分4類,見上圖。


BootStrapClassLoader:加載jre/lib下的jdk的jar包,具有超級權限,是最頂級的類加載器;


ExtensionClassLoader:加載jre/lib/ext下的jar包,加載jdk的擴展程序包;


ApplicationClassLoader:加載當前應用classpath下的jar包或者class文件;


自定義ClassLoader:用戶自定義的類加載器,一般是為了進行進程隔離,或者自己操縱字節碼;


雙親委派機制:即為了避免類信息被重複加載和程序的安全性,父加載器優先子加載器加載類型到jvm,子加載器無法加載父加載器已經加載到jvm中的類型信息。


下面做一下擴展:針對面試官可能會追問的細節。

類加載器體系

面試刷題23:類加載過程和雙親委派機制?


指定超級加載器的目錄和時機:


指定新的bootclasspath,替換java.*包的內部實現

<code>java -Xbootclasspath: your_App/<code>

a意味著append,將指定目錄添加到bootclasspath後面

<code>java -Xbootclasspath/a: your_App/<code>

p意味著prepend,將指定目錄添加到bootclasspath前面

<code>java -Xbootclasspath/p: your_App/<code>


指定擴展加載器的目錄:

<code>java -Djava.ext.dirs=your_ext_dir HelloWorld/<code>


指定系統加載器的實現類:

<code>java -Djava.system.class.loader=com.yourcorp.YourClassLoader HelloWorld/<code>


打印出類加載器:

<code>java package org.example.mianshi.classloader;

import java.util.Collection;

/**

作者: carter


創建日期: 2020/3/31 12:41

描述: 類加載器的層級關係

/

public class PrintClassLoaderApp {
public static void main(String[] args) {

System.out.println("PrintClassLoaderApp 的類加載器是:"+PrintClassLoaderApp.class.getClassLoader());
System.out.println("parent 的類加載器是:"+ PrintClassLoaderApp.class.getClassLoader().getParent());
System.out.println("parent.parent 的類加載器是:"+ PrintClassLoaderApp.class.getClassLoader().getParent().getParent());
System.out.println("Collection 的類加載器是:"+ Collection.class.getClassLoader());

}
}/<code>

輸出結果:

我使用的java10,PlatformClassLoader替代了ExtensionClassLoader;

<code>PrintClassLoaderApp 的類加載器是:jdk.internal.loader.ClassLoaders$AppClassLoader@4459eb14
parent 的類加載器是:jdk.internal.loader.ClassLoaders$PlatformClassLoader@2ac1fdc4
parent.parent 的類加載器是:null
Collection 的類加載器是:null/<code>


自定義類加載器

自定義類加載器一般用來進行進程內隔離,或者需要自己操縱字節碼的場景。

過程如下:
1,通過名稱找到二進制代碼,即class文件;


2,使用class文件創建對應的class對象;


示例代碼如下:

<code>package org.example.mianshi.classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
* 作者: carter
* 創建日期: 2020/3/31 14:24
* 描述: 自定義類加載器
*/

public class CustomerClassLoaderApp extends ClassLoader {

@Override
protected Class> findClass(String name) throws ClassNotFoundException {

byte[] bytes = loadClassFromFile(name);

return defineClass(name, bytes, 0, bytes.length);
}

private byte[] loadClassFromFile(String name) {

InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream(name.replace(".", File.separator) + ".class");

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int nextValue = 0;
try {
while ((nextValue = inputStream.read()) != -1) {
byteArrayOutputStream.write(nextValue);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] buffer = byteArrayOutputStream.toByteArray();


return buffer;
}

}/<code>


如何加速類加載


1, AOT , 即提前把字節碼編譯成機器碼,然後在啟動的時候指定機器碼的位置,
2,AppCDS ,即提前把類信息加載成為元數據,使用內存映射技術,免除類加載和解析的開銷。

小結


本節回顧了jvm的類加載過程,類加載器的層次,雙親委派原則,
然後指明瞭自定義類加載器的使用場景和基本過程,以及給了一個簡單的例子;
最後給出了兩種加速類加載器速度的方法。

面試刷題23:類加載過程和雙親委派機制?


分享到:


相關文章: