Class類的實例表示正在運行的Java應用程序中的類或接口. Class類沒有公共構造函數,那他是如何建立的呢? 咱們來看看官方文檔是如何說的java
Instead {@code Class} objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the {@code defineClass} method in the class loader.c++
Class對象是由Java虛擬機在加載類時自動構造的,並經過調用類加載器中的defineClass方法來構造. 每一個Class對象包含一個定義他的類加載器的引用.jvm
private final ClassLoader classLoader;
函數
下面咱們就來認識一下類加載器.this
看看jdk文檔怎麼說:spa
A class loader is an object that is responsible for loading classes.Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the classdebug
類加載器是負責加載類的對象,給定一個類的全限定名,類加載應該嘗試生成包含在類定義裏面的數據流 通俗點解釋就是: .java文件編譯後生成.class文件, 類加載器就是將.class文件轉換成java.lang.Class類的一個實例3d
負責加載系統類,由c語言實現,沒有對應的類加載器 加載路徑: System.getProperty("sun.boot.class.path");
code
負責加載擴展類 加載路徑 System.getProperty("java.ext.dirs");
cdn
從用戶類路徑下加載 加載路徑 System.getProperty("java.class.path");
System.out.println(String.class.getClassLoader()); // 加載系統類用到的類加載器
System.out.println(Student.class.getClassLoader()); // Student是用戶自定義的類
複製代碼
輸出一下查看結果
null
sun.misc.Launcher$AppClassLoader@18b4aac2
複製代碼
由於String是系統類,因此由BootstrapClassLoader加載,而BootstrapClassLoader沒有對應的類加載器,因此爲null
Student是在用戶類路徑下定義的,因此是由AppClassLoader加載
除了啓動類加載器外,全部的類加載器都有一個父類加載器。類加載器要先把加載類的機會交給他的父類加載器。在父類加載器加載失敗時,他纔會加載該類
類加載器層次結構圖:
加載Studeng類的過程: AppClassLoader先交給其父類ExtentsionClassLoader加載,ExtensionClassLoader交給他的父類BootstrapClassLoader加載,BootstrapClassLoader沒有父類加載器,嘗試加載,加載失敗,讓其子類ExtensionClassLoader加載,一樣加載失敗,交給其子類AppClassLoader加載,加載成功!
Launcher類是java應用的入口,由JVM建立的,源碼對外隱藏,只能經過反編譯查看. 爲何Launcher類是java應用的入口? 由於 ApplicationClassLoader和ExtClassLoader都是在Launcher類定義的
ClassLoader類的loadClass()方法
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 加鎖機制
synchronized (getClassLoadingLock(name)) {
// 給定一個類的全限定名,檢查類是否被加載過,底層調用的c++方法,不須要深刻研究
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 先讓其父類加載
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// 父類爲空,則讓BootStrapClassLoader加載該類
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
long t1 = System.nanoTime();
// 經過類的全限定名查找該類
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;
}
}
複製代碼
你們本身都debug幾遍,就能搞懂雙親委派機制的流程,我就不貼圖了,求關注
關注公衆號,免費領取優秀jvm入門書籍