這篇文章主要介紹“Java中的ClassLoader核心知識(shí)點(diǎn)有哪些”,在日常操作中,相信很多人在Java中的ClassLoader核心知識(shí)點(diǎn)有哪些問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Java中的ClassLoader核心知識(shí)點(diǎn)有哪些”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
成都創(chuàng)新互聯(lián)專注于市南網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供市南營(yíng)銷型網(wǎng)站建設(shè),市南網(wǎng)站制作、市南網(wǎng)頁(yè)設(shè)計(jì)、市南網(wǎng)站官網(wǎng)定制、小程序定制開(kāi)發(fā)服務(wù),打造市南網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供市南網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。
JDK 和 JRE 的作用
JDK 提供了 java 的編程環(huán)境,它包含編譯調(diào)試的環(huán)境功能,包含 JRE(JDK 目錄中的 JRE 為專用 JRE,而安裝后與 JDK 同目錄的 JRE 為公用 JRE)。開(kāi)發(fā)時(shí)一般運(yùn)行的是 JDK 專用JRE,而運(yùn)行外部程序時(shí)一般運(yùn)行的是公用 JRE,實(shí)現(xiàn)了分工不同的 jre 負(fù)責(zé)各自范圍的內(nèi)容。
JRE 提供了 JAVA 程序運(yùn)行的必要環(huán)境平臺(tái)
JAVAHOME、PATH、CLASSPATH
JAVAHOME: JDK安裝的位置路徑,如:D:\Program Files\Java\jdk1.8.0_241
PATH: 配置后運(yùn)行 bin 中的命令不需要補(bǔ)全全路徑,如可以在任意的位置運(yùn)行 java 和 javac 命令, %JAVA_HOME%\bin;
CLASSPATH:指向jar包路徑 %JAVA_HOME%\lib;
類加載器的種類
在JVM中有三類ClassLoader構(gòu)成:
Bootstrap ClassLoader 啟動(dòng)類(或根類)加載器
Extention ClassLoader 擴(kuò)展的類加載器
Appclass Loader 應(yīng)用類加載器
(1) Bootstrap ClassLoader
Bootstrap ClassLoader 最頂層的類加載器,主要加載核心類庫(kù) %JRE_HOME%\lib 下的 rt.jar、resources.jar、charsets.jar 和 class文件等。
//執(zhí)行 System.out.println(System.getProperty("sun.boot.class.path")); //輸出結(jié)果 D:\Program Files\Java\jdk1.8.0_241\jre\lib\resources.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\rt.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\sunrsasign.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\jsse.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\jce.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\charsets.jar; D:\Program Files\Java\jdk1.8.0_241\jre\lib\jfr.jar; D:\Program Files\Java\jdk1.8.0_241\jre\classes
(2) Extention ClassLoader
Extention ClassLoader 擴(kuò)展的類加載器,主要加載目錄 %JRE_HOME%\lib\ext 目錄下的jar包和class文件。
//執(zhí)行 System.out.println(System.getProperty("java.ext.dirs")); //輸出 D:\Program Files\Java\jdk1.8.0_241\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
(3) Appclass Loader
Appclass Loader也稱為SystemAppClass 加載當(dāng)前應(yīng)用的classpath的所有類。
類加載器的執(zhí)行順序
除啟動(dòng)類加載器(Bootstrap ClassLoader)外,擴(kuò)展類加載器和應(yīng)用類加載器都是通過(guò)類sun.misc.Launcher進(jìn)行初始化,而Launcher類則由啟動(dòng)類加載器進(jìn)行加載。Launcher相關(guān)代碼如下:
public Launcher() { Launcher.ExtClassLoader var1; try { //初始化擴(kuò)展類加載器,構(gòu)造函數(shù)沒(méi)有入?yún)?,無(wú)法獲取啟動(dòng)類加載器 var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try { //初始化應(yīng)用類加載器,入?yún)閿U(kuò)展類加載器 this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } // 設(shè)置上下文類加載器 Thread.currentThread().setContextClassLoader(this.loader); //... }
加載順序:Bootstrap CLassloder > Extention ClassLoader > AppClassLoader
父加載器概念
AppClassLoader 和 ExtClassLoader 都繼承了 URLClassLoader。每個(gè)類加載器都有一個(gè)父加載器(注意:父類和父加載器是兩個(gè)不同的概念),可通過(guò) getParent() 獲取父類加載器。
System.out.println("ClassLoader is:"+cl.toString()); System.out.println("ClassLoader\'s parent is:"+cl.getParent().toString());System.out.println("ClassLoader\'s grand father is:"+cl.getParent().getParent().toString());
AppClassLoader 的父加載器是ExtClassLoader
ExtClassLoader的父加載器是Bootstrap ClassLoader(上面代碼輸出 ExtClassLoader 為null 是因?yàn)? Bootstrap ClassLoader 本身不是一個(gè)Java 類所致)
Bootstrap ClassLoader是由C/C++編寫的,它本身是虛擬機(jī)的一部分,所以它并不是一個(gè)JAVA類,也就是無(wú)法在java代碼中獲取它的引用,JVM啟動(dòng)時(shí)通過(guò)Bootstrap類加載器加載rt.jar等核心jar包中的class文件,之前的int.class,String.class都是由它加載。然后呢,我們前面已經(jīng)分析了,JVM初始化sun.misc.Launcher并創(chuàng)建Extension ClassLoader和AppClassLoader實(shí)例。并將ExtClassLoader設(shè)置為AppClassLoader的父加載器。Bootstrap沒(méi)有父加載器,但是它卻可以作用一個(gè)ClassLoader的父加載器。
雙親委派
雙親委派模型:當(dāng)一個(gè)類加載器接收到類加載請(qǐng)求時(shí),會(huì)先請(qǐng)求其父類加載器加載,依次遞歸,當(dāng)父類加載器無(wú)法找到該類時(shí)(根據(jù)類的全限定名稱),子類加載器才會(huì)嘗試去加載。
時(shí)序圖
為什么使用雙親委派模型?
雙親委派模型是為了保證Java核心庫(kù)的類型安全。所有Java應(yīng)用都至少需要引用java.lang.Object類,在運(yùn)行時(shí)這個(gè)類需要被加載到Java虛擬機(jī)中。如果該加載過(guò)程由自定義類加載器來(lái)完成,可能就會(huì)存在多個(gè)版本的java.lang.Object類,而且這些類之間是不兼容的。
通過(guò)雙親委派模型,對(duì)于Java核心庫(kù)的類的加載工作由啟動(dòng)類加載器來(lái)統(tǒng)一完成,保證了Java應(yīng)用所使用的都是同一個(gè)版本的Java核心庫(kù)的類,是互相兼容的。
自定義類加載器
不管是Bootstrap ClassLoader還是ExtClassLoader等,這些類加載器都只是加載指定的目錄下的jar包或者資源。如果我們需要?jiǎng)討B(tài)加載比如從指定目錄中加載一個(gè)class文件,這時(shí)候通過(guò)自定義類加載器可以實(shí)現(xiàn)。
自定義類加載器只需要繼承java.lang.ClassLoader類,然后重寫findClass(String name)方法即可,在方法中指明如何獲取類的字節(jié)碼流。如果要破壞雙親委派規(guī)范的話,還需重寫loadClass方法(雙親委派的具體邏輯實(shí)現(xiàn))。但不建議這么做。
public class ClassLoaderTest extends ClassLoader { private String classPath; public ClassLoaderTest(String classPath) { this.classPath = classPath; } /** * 編寫findClass方法的邏輯 * * @param name * @return * @throws ClassNotFoundException */ @Override protected Class> findClass(String name) throws ClassNotFoundException { // 獲取類的class文件字節(jié)數(shù)組 byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { // 生成class對(duì)象 return defineClass(name, classData, 0, classData.length); } } /** * 編寫獲取class文件并轉(zhuǎn)換為字節(jié)碼流的邏輯 * * @param className * @return */ private byte[] getClassData(String className) { // 讀取類文件的字節(jié) String path = classNameToPath(className); try { InputStream is = new FileInputStream(path); ByteArrayOutputStream stream = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int num = 0; // 讀取類文件的字節(jié)碼 while ((num = is.read(buffer)) != -1) { stream.write(buffer, 0, num); } return stream.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 類文件的完全路徑 * * @param className * @return */ private String classNameToPath(String className) { return classPath + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; } public static void main(String[] args) { String classPath = "/Users/zzs/my/article/projects/java-stream/src/main/java/"; ClassLoaderTest loader = new ClassLoaderTest(classPath); try { //加載指定的class文件 Class> object1 = loader.loadClass("com.secbro2.classload.SubClass"); System.out.println(object1.newInstance().toString()); } catch (Exception e) { e.printStackTrace(); } } }
到此,關(guān)于“Java中的ClassLoader核心知識(shí)點(diǎn)有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!