Java的程序要運行須要將編譯好的class文件加載到JVM運行時數據區。java
在瞭解類的加載機制以前,咱們須要瞭解一下類的生命週期。Java類從被加載到JVM內存開始,到卸載出內存爲止,它的整個生命週期包括了:加載(Loading),驗證(Verification),準備(Preparation),解析(Resolution),初始化(Initialization),使用(Using)和卸載(Unloading)七個階段。安全
Java類的加載須要用到類加載器。類加載器負責裝入類,搜索網絡,jar,zip,文件夾,二進制數據,內存等指定位置的資源。一個Java程序運行,至少有3個不一樣的類加載器實例,負責加載不一樣的類。這三個類加載器分別爲,啓動類加載器(Bootstrap ClassLoader),擴展類加載器(Extension ClassLoader),應用程序類加載器(Application ClassLoader)。markdown
經過JDK提供的API:java.lang.Class.getClassLoader() 能夠進行類加載器的查看,該API會返回裝載類的類加載器,若是這個類是由Bootstrap ClassLoader加載的,那個這個方法會返回null。網絡
代碼示例:app
public class ClassLoaderView { public static void main(String[] args) throws Exception { // 加載核心類庫的 BootStrap ClassLoader System.out.println( "核心類庫加載器:" + ClassLoaderView.class .getClassLoader() .loadClass("java.lang.String") .getClassLoader()); // 加載拓展庫的 Extension ClassLoader System.out.println( "拓展類庫加載器:" + ClassLoaderView.class .getClassLoader() .loadClass("com.sun.nio.zipfs.ZipCoder") .getClassLoader()); // 加載應用程序的 Application ClassLoader System.out.println("應用程序庫加載器:" + ClassLoaderView.class.getClassLoader()); } } //運行結果: 核心類庫加載器:null 拓展類庫加載器:sun.misc.Launcher$ExtClassLoader@7f31245a 應用程序庫加載器:sun.misc.Launcher$AppClassLoader@18b4aac2
class信息能夠存在不一樣的地方,那麼JVM是如何知道咱們的類存在什麼地方的哪?經過查看sun.misc.Launcher.AppClassLoader的源碼咱們能夠看到,它會讀取java.class.path這個配置來獲取那些地址加載類資源。參考如下代碼示例,利用jsp和jcmd兩個命令能夠進行驗證。jvm
代碼示例:jsp
public class HelloWord { public static void main(String[] args) throws IOException { System.out.println("Hello Word"); System.in.read(); } }
jsp命令能夠查看本機Java進程,jcmd命令能夠查看運行時配置:jcmd 進程號 VM.system_propertiesui
Java中的類並不會重複加載,同一類加載器,同一類名,表明的是同一個類。而避免類重複加載的主要緣由在於JVM在加載類時默認採用的是雙親委派模型。所謂的雙親委派模型,就是某個特定的類加載器在接到類的加載請求時,首先將加載任務委託給父加載器,依次遞歸,若是父加載器能夠完成類加載任務,就成功返回;只有父加載器沒法完成此加載任務時,才本身去加載。由下到上逐級委託,由上到下逐級查找,雙親委派模型保證了Java核心庫的類型安全url
JVM中的類不可能一直存在,在知足必定條件的狀況下類會被卸載掉。在知足該Class的全部實例都已被垃圾回收,同時加載該類的ClassLoader實例也已經被垃圾回收,那麼這個類會被JVM卸載掉。在JVM啓動中增長-verbose:class參數,能夠輸出類加載和卸載的日誌信息。spa