摘要:當一個文件是通過網(wǎng)絡(luò)傳輸并且可能會進行相應(yīng)的加密操作時,需要先對文件進行相應(yīng)的解密后再加載到內(nèi)存中,這種情況下也需要編寫自定義的并實現(xiàn)相應(yīng)的邏輯
Java虛擬機中的類加載有三大步驟:,鏈接,初始化.其中加載是指查找字節(jié)流(也就是由Java編譯器生成的class文件)并據(jù)此創(chuàng)建類的過程,這中間我們需要借助類加載器來查找字節(jié)流.
Java虛擬機默認類加載器Java虛擬機提供了3種類加載器,啟動(Bootstrap)類加載器、擴展(Extension)類加載器、應(yīng)用(Application)類加載器.除了啟動類加載器外,其他的類加載器都是java.lang.ClassLoader的子類.啟動類加載器由C++語言實現(xiàn),沒有對應(yīng)的Java對象,它負責將
注意這里面的父子類加載器并不是繼承的關(guān)系,只是ClassLoader類中的parent屬性.我們來看Launcher類中創(chuàng)建擴展類加載器的代碼:
public ExtClassLoader(File[] var1) throws IOException { super(getExtURLs(var1), (ClassLoader)null, Launcher.factory); SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this); }
這里設(shè)置了其父加載器為null.
雙親委派機制Java虛擬機在加載類時默認采用的是雙親委派機制,即當一個類加載器接收到加載請求時,會將請求轉(zhuǎn)發(fā)到父類加載器,如果父類加載器在路徑下沒有找到該類,才會交給子類加載器去加載.我們來看ClassLoader中l(wèi)aodClass方法:
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先判斷類是否已加載過,加載過就直接返回 Class> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { //有父類加載器,調(diào)用父加載器的loadClass c = parent.loadClass(name, false); } else { //調(diào)用Bootstrap Classloader c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { long t1 = System.nanoTime(); //到自己指定類加載路徑下查找是否有class字節(jié)碼 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) { resolveClass(c); } return c; } }
通過這種層級我們可以避免類的重復(fù)加載,當父親已經(jīng)加載了該類時,就沒有必要子類加載器再加載一次。其次也考慮到安全因素,比如我們自己寫一個java.lang.String的類,通過雙親委派機制傳遞到啟動類加載器,而啟動類加載器在核心Java API發(fā)現(xiàn)這個名字的類,發(fā)現(xiàn)該類已被加載,并不會重新加載我們新寫的java.lang.String,而直接返回已加載過的String.class,這樣保證生成的對象是同一種類型.
自定義類加載器除了jvm自身提供的類加載器,我們還可以自定義類加載器,我們先寫一個Person類
public class Person { private int age; private String name; //省略getter/setter方法 }
我們先看他是由哪個類加載器加載的.
public class TestJava { public static void main(String[] args) throws Exception { Person person = new Person(); System.out.println("person是由" + person.getClass().getClassLoader() + "加載的"); } }
運行結(jié)果如下:
我們把Person.class放置在其他目錄下
再運行會發(fā)生什么,在上面的loadClass方法中其實已經(jīng)有了答案,會拋出ClassNotFoundException,因為在指定路徑下查找不到字節(jié)碼.
我們現(xiàn)在寫一個自定義的類加載器,讓他能夠去加載person類,很簡單,我們只需要繼承ClassLoader并重寫findClass方法,這里面寫查找字節(jié)碼的邏輯.
public class PersonCustomClassLoader extends ClassLoader { private String classPath; public PersonCustomClassLoader(String classPath) { this.classPath = classPath; } private byte[] loadByte(String name) throws Exception { name = name.replaceAll(".", "/"); FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class"); int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } protected Class> findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); return defineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(); } } }
我們來測試一下:
public class TestJava { public static void main(String[] args) throws Exception { PersonCustomClassLoader classLoader = new PersonCustomClassLoader("/home/shenxinjian"); Class> pClass = classLoader.loadClass("me.shenxinjian.algorithm.Person"); System.out.println("person是由" + pClass.getClassLoader() + "類加載器加載的"); } }
測試結(jié)果如下:
當class文件不在classPath路徑下,如上面那種情況,默認系統(tǒng)類加載器無法找到該class文件,在這種情況下我們需要實現(xiàn)一個自定義的classLoader來加載特定路徑下的class文件來生成class對象。
當一個class文件是通過網(wǎng)絡(luò)傳輸并且可能會進行相應(yīng)的加密操作時,需要先對class文件進行相應(yīng)的解密后再加載到JVM內(nèi)存中,這種情況下也需要編寫自定義的ClassLoader并實現(xiàn)相應(yīng)的邏輯
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/73405.html
摘要:它負責將的字節(jié)碼形式轉(zhuǎn)換成內(nèi)存形式的對象。先使用工具對字節(jié)碼文件進行加密,運行時使用定制的先解密文件內(nèi)容再加載這些解密后的字節(jié)碼。的方法是需要子類來覆蓋的,不同的加載器將使用不同的邏輯來獲取目標類的字節(jié)碼。 ClassLoader 詳解 ClassLoader 做什么的? 延遲加載 各司其職 ClassLoader 傳遞性 雙親委派 Class.forName 自定義加載器 Clas...
摘要:加載器種類啟動類加載器在中用來加載自身需要的類,實現(xiàn),用來加載。那么就能保證的類會被優(yōu)先加載,限制了使用者對系統(tǒng)的影響。這種方式下就完成類加載器的雙親委派機制此處會將作為參數(shù)傳入進去實際上是調(diào)用了方法 Class 文件的裝載流程 (類加載過程) 加載 -> 連接 (驗證 -> 準備 -> 解析) -> 初始化 -> 使用 -> 卸載 加載 加載階段,jvm 會通過類名獲取到此類的字節(jié)碼...
摘要:如問到是否使用某框架,實際是是問該框架的使用場景,有什么特點,和同類可框架對比一系列的問題。這兩個方向的區(qū)分點在于工作方向的側(cè)重點不同。 [TOC] 這是一份來自嗶哩嗶哩的Java面試Java面試 32個核心必考點完全解析(完) 課程預(yù)習 1.1 課程內(nèi)容分為三個模塊 基礎(chǔ)模塊: 技術(shù)崗位與面試 計算機基礎(chǔ) JVM原理 多線程 設(shè)計模式 數(shù)據(jù)結(jié)構(gòu)與算法 應(yīng)用模塊: 常用工具集 ...
摘要:反射機制的應(yīng)用實例在泛型為的中存放一個類型的對象。工廠模式可以參考現(xiàn)在我們利用反射機制實現(xiàn)工廠模式,可以在不修改工廠類的情況下添加任意多個子類。 學(xué)習交流群:669823128java 反射 定義 功能 示例概要:Java反射機制詳解| |目錄 1反射機制是什么 2反射機制能做什么 3反射機制的相關(guān)API 通過一個對象獲得完整的包名和類名 實例化Class類對象 獲取一個對象的父類與...
摘要:再附一部分架構(gòu)面試視頻講解本文已被開源項目學(xué)習筆記總結(jié)移動架構(gòu)視頻大廠面試真題項目實戰(zhàn)源碼收錄 Java反射(一)Java反射(二)Java反射(三)Java注解Java IO(一)Java IO(二)RandomAccessFileJava NIOJava異常詳解Java抽象類和接口的區(qū)別Java深拷貝和淺拷...
閱讀 642·2021-11-25 09:43
閱讀 1654·2021-11-18 10:02
閱讀 1033·2021-10-15 09:39
閱讀 1877·2021-10-12 10:18
閱讀 2114·2021-09-22 15:43
閱讀 755·2021-09-22 15:10
閱讀 2083·2019-08-30 15:53
閱讀 977·2019-08-30 13:00