多個java文件通過編譯打包生成可運行的jar包,最終由java命令運行某個主類的main函數啓動程序,這裏首先須要經過類加載器把主類加載到jvm。
主類在運行過程當中若是使用到其餘類,會逐步加載這些類。
注意,jar包裏的類不是一次性所有加載的,是使用時才加載的。java
從類加載到使用整個過程由以下幾步:
加載、驗證、準備、解析、初始化、使用、卸載web
初始化:對類的靜態變量初始化爲指定的值,執行靜態代碼塊。
編程
自定義加載器:負責加載用戶自定義路徑下的類包;後端
類記載器繼承了java.lang.ClassLoader類,該類有兩個核心方法,loadClass和findClass。機器學習
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. 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; } }
findClass方法默認實現是拋出異常,因此咱們在自定義類加載器主要是重寫findClass方法。jvm
protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }
jvm類加載器是有親子層結構的.編程語言
這裏類加載就是雙親委派機制,記載某個類時, 會先委託父加載器尋找目標類,找不到再委託上層父加載器加載,若是全部父加載器再本身的加載類路徑下都找不到目標類,則再本身的類加載路徑中查找並載入目標類。函數
好比:Math類,最早會找應用程序類加載器加載,應用程序加載器會先委託擴展類加載器加載,擴展類加載器再委託啓動類加載器,頂層啓動類加載器在本身的類加載器路徑裏找了半天沒找到Math類,則向下退回加載Math類的請求,擴展類加載器收到回覆就本身加載,在本身的類加載路徑裏找了半天也沒找到Math類,又向下退回Math類的加載請求給應用程序類加載器,應用程序類加載器因而在本身的類加載路徑中找到了Math類,因而就本身加載了。工具
雙親委派機制說簡單就是:先找父親加載,不行再由父親本身加載。學習
還沒關注個人公衆號?