首頁>技術>

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中的型別資訊。

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

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

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

java -Xbootclasspath: your_App
a意味著append,將指定目錄新增到bootclasspath後面
java -Xbootclasspath/a: your_App
p意味著prepend,將指定目錄新增到bootclasspath前面
java -Xbootclasspath/p: your_App

指定擴充套件載入器的目錄:

java -Djava.ext.dirs=your_ext_dir HelloWorld

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

java -Djava.system.class.loader=com.yourcorp.YourClassLoader HelloWorld

打印出類載入器:

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());}}

輸出結果:

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

PrintClassLoaderApp 的類載入器是:jdk.internal.loader.ClassLoaders$AppClassLoader@4459eb14parent 的類載入器是:jdk.internal.loader.ClassLoaders$PlatformClassLoader@2ac1fdc4parent.parent 的類載入器是:nullCollection 的類載入器是:null
自定義類載入器

自定義類載入器一般用來進行程序內隔離,或者需要自己操縱位元組碼的場景。

過程如下:1,通過名稱找到二進位制程式碼,即class檔案;2,使用class檔案建立對應的class物件;

示例程式碼如下:

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;    }}
如何加速類載入

1, AOT , 即提前把位元組碼編譯成機器碼,然後在啟動的時候指定機器碼的位置,2,AppCDS ,即提前把類資訊載入成為元資料,使用記憶體對映技術,免除類載入和解析的開銷。

小結

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

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 為什麼我不推薦你以python入門