本文是筆者在學習Java 類加載的過程當中,整理的心得體會,共勉!java
簡單概念:網絡
將Java類的.class文件中的二進制數據讀入到內存中,放置在運行時數據區的方法區內。jvm
何時會進行類加載?函數
本地系統加載;學習
代理加載,好比Spring的AOP動態代理;測試
從jar包中加載;this
等等等等加密
ClassLoader是一個抽象類,核心方法以下:spa
defineClass():目的是將byte字節流解析成JVM可以識別的Class對象。命令行
findClass():此方法支持重載,與defineClass()配合使用,目的是獲取Class對象的字節碼。這個方法的意義在於,咱們不只僅能夠經過class文件實例化對象,也能夠經過其餘方式,好比從網絡上獲取的字節碼文件,可能會有對應的加密規則。
loadClass():此方法支持重載,目的是獲取加載類的類對象。
resolveClass():實現讓JVM連接這個類,此方法調用的是本地方法,不能重載。
今生命週期對應到ClassLoader類的具體方法:
加載:loadClass()、findClass()、defineClass()
鏈接:包括驗證、準備、解析:resolveClass() 本地native方法
初始化:JVM負責
概念介紹:
大體的ClassLoader分類:
心得體會:
這裏的父加載器與子加載器 在java類關係上並非繼承關係;
實現本身的類加載器,不論是直接實現抽象類ClassLoader,仍是繼承其餘子類,父加載器都是AppClassLoader;
一、命令行啓動應用時候由JVM初始化加載
二、經過Class.forName()方法動態加載
三、經過ClassLoader.loadClass()方法動態加載
Class.forName()和ClassLoader.loadClass()區別
Class.forName():將類的.class文件加載到jvm中以外,還會對類進行解釋,執行類中的static塊;
ClassLoader.loadClass():只幹一件事情,就是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance纔會去執行static塊。
Class.forName(name,initialize,loader)帶參函數也可控制是否加載static塊。而且只有調用了newInstance()方法採用調用構造函數,建立類的對象
基於上面對於類加載器的分析,自定義ClassLoader的狀況以下:
從上面的分析咱們還能夠獲得,自定義ClassLoader的實現思路能夠經過繼承ClassLoader類,重寫findClass()來實現,固然你也能夠重寫loadClass(),可是默認的loadClass()是實現類加載雙親委託模式的,除非你想要破壞這種雙親委託模式,否則就別重寫了。
下面是我在本機寫的測試自定義ClassLoader的Demo:
/** * 自定義路徑下的class文件加載 * @Auther: trey_stao@163.com * @Date: 2018/5/31 19:34 * @Description: */ public class PathClassLoader extends ClassLoader { private String classPath; public PathClassLoader(String classPath) { this.classPath = classPath; } private String packageName = "com.trey.classloader.Test"; protected Class<?> findClass(String name) throws ClassNotFoundException { if(packageName.startsWith(name)) { byte[] classData = getData(name); if(classData == null) { throw new ClassNotFoundException(); } else { System.out.println("當前類加載器:"+this.getClass().getClassLoader().toString()); return defineClass(name, classData, 0, classData.length); } } else { return super.loadClass(name); } } private byte[] getData(String name) { String path = classPath + File.separatorChar + name.replace('.',File.separatorChar) + ".class"; try { InputStream is = new FileInputStream(path); ByteArrayOutputStream stream = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int num = 0; while ((num = is.read(buffer)) != -1) { stream.write(buffer, 0, num); } return stream.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } }
這是給本身佈置的對類加載學習的總結練習。下面說下本身準備實現的思路:
整理這篇學習心得時,參考了一些文章,特在此註明,表示感謝!
周志明:《深刻理解Java虛擬機:JVM高級特性與最佳實踐》
純潔的微笑:java類的加載機制
許令波:《深刻分析Java Web 技術內幕》