![面試刷題23:類加載過程和雙親委派機制?](http://p2.ttnews.xyz/loading.gif)
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:類加載過程和雙親委派機制?](http://p2.ttnews.xyz/loading.gif)
指定超級加載器的目錄和時機:
指定新的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的類加載過程,類加載器的層次,雙親委派原則,
然後指明瞭自定義類加載器的使用場景和基本過程,以及給了一個簡單的例子;
最後給出了兩種加速類加載器速度的方法。
閱讀更多 李福春 的文章