Reference:html
[1] http://www.cnblogs.com/kevin2chen/p/6714214.htmljava
當調用 java命令運行一個java程序時,會啓動一個java虛擬機進程。同一個jvm的全部線程、全部變量都處於同一個進程裏,都使用該jvm進程的內存區。 jvm進程終止,jvm內存中的數據將所有丟失。c++
jvm進程終止的狀況:web
1.程序運行到最後正常結束。api
2.遇到System.exit()或Runtime.getRuntime.exit()。數組
3.遇到未捕獲的異常或錯誤安全
4.程序所在的平臺強制結束了JVM進程網絡
當程序主動使用某個類時,若是該類還未被加載到內存中,系統會進行類加載。類加載指的是將類的class文件讀入內存,併爲之建立一個java.lang.Class的實例。由於java中萬物皆爲對象,類也是java.lang.Class類型的對象。數據結構
類加載具體有加載、鏈接和初始化3個步驟,加載階段須要完成的事情有:app
1)經過一個類的全限定名來獲取定義此類的二進制字節流。
2)將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構。
3)在java堆中生成一個表明這個類的Class對象,做爲訪問方法區中這些數據的入口。
類的加載,是由類加載器來完成的,類加載器一般由JVM提供。經過使用不一樣的類加載器,能夠加載如下不一樣來源的類的二進制數據:
1.從本地文件系統加載class文件
2.從jar包中直接加載class文件
3.經過網絡加載class文件
4.把一個java源文件動態編譯並加載
負責把類的二進制數據合併到JRE(java運行環境)中
1.驗證:檢測被加載的類是否有正確的內部結構,是否被破壞或包含不良代碼,並和其餘類協調一致
2.準備:負責爲類的靜態屬性分配內存,並設置默認初始值
3.解析:將類的二進制數據中的符號引用替換成直接引用
主要對類的靜態屬性進行初始化。能夠在聲明靜態屬性時指定初始值和經過靜態初始化塊指定初始值,JVM會按照這些語句在程序中的順序依次執行。
每一個類加載器(除了根類加載器)都是java.lang.ClassLoader的實例,負責將.class文件加載到內存中,併爲之生成對應的java.lang.Class對象。
同一個.class不會被同一個類加載器加載兩次,如何判斷是同一個類: java中,一個類用其全限定類名標識--包名+類名;jvm中,一個類用其全限定類名+其類加載器標識---包名+類名+類加載器名
加載器層次結構:
JVM啓動時,會造成由三個類加載器組成的初始類加載器層次結構:
1.Bootstrap ClassLoader 根類加載器(引導類加載器),加載java的核心類(限定的加載路徑:jdk1.8_02/jre/lib/rt.jar)。它不是java.lang.ClassLoader的子類,而是由JVM自身實現的。虛擬機爲了安全性以及功能的完整性,並非任何存在於啓動類加載器路徑下的jar都會被加載,只有可信類(trusted classes )會被加載,因此開發者不要將自定義的類放在此目錄。
2.Extension ClassLoader 擴展類加載器,加載JRE的擴展目錄中JAR的類包(限定的加載路徑:%JAVA_HOME%/jre/lib/ext/或java.ext.dirs系統屬性指定的目錄)
3.System ClassLoader 系統類加載器,加載java.class.path系統屬性或CLASSPATH環境變量所指定的jar包和類路徑,可經過ClassLoader的靜態方法ClassLoader.getSystemClassLoader()獲取系統類加載器。若是沒有特別指定,用戶自定義的類加載器以該類加載器做爲它的父加載器。也能夠經過Class實例的getClassLoader()方法當前類的類加載器。
4.自定義類加載器
JVM系統自帶的類加載器在程序運行中只能加載對應路徑的.class文件,沒法改變其搜索路徑。若是想在運行時從其餘路徑加載類,就要編寫自定義的類加載器。
1.全盤負責:某類所依賴及其引用的全部類,都由同一個加載器負責加載,除非顯示使用另一個加載器。
2.雙親委託: 當一個類加載器收到類加載的請求,首先將請求委派給父類加載器,遞歸到Bootstrap ClassLoader。而後加載器根據請求嘗試搜索和加載類,若沒法加載該類時則向子類加載器反饋信息(拋出ClassNotFoundException),由子類加載器本身去加載。
類加載期之間的父子關係並非類繼承上的父子關係,是採用組合的方式實現雙親委派模型的。
根類加載器是由c++實現的,不是由java語言實現,沒有繼承ClassLoader,因此擴展類加載器調用parent()返回的是null。但擴展類加載器實際上仍能夠委派給根類加載器。
使用雙親委託模式的緣由:被父類加載器加了的類能夠避免避免被子類從新加載,由於在JVM中由全限定名+類加載器名標識類。另外能夠避免加載到同sun公司核心API同名的惡意類。
JVM中除了根加載器以外,全部類加載器都是ClassLoader子類的實例,開發者經過擴展ClassLoader並重寫ClassLoader所包含的方法來實現自定義的類加載器。
如上源碼所示,loadClass()方法內部主要是雙親委派模型的實現,在最後調用findClass()方法加載類,因此自定義類加載器重寫findClass()比重寫loadClass()方便,能夠避免覆蓋默認類加載器的父類委託和緩衝機制兩種策略。
ClassLoader類的核心方法:
protected synchronized Class<?> loadClass(String name, boolean resolve)根據指定的binary name(由兩個不一樣部分組成的名字,即全限定類名)來加載類,返回Class對象。
protected Class<?> findClass(String name)根據二進制名稱來查找類,返回Class對象。此方法應該被自定義類加載器的實現重寫,在經過父類加載器檢查所請求的類後,被loadClass方法調用。
final defineClass(String name,byte[] b,int off,int len)將指定類的字節碼文件讀入字節數組內,並把它轉爲Class實例,該字節碼文件能夠來源於網絡或本地。
findLoadedClass(String name)返回jvm裝載的name類的Class實例,若無返回null。
static getSystemClassLoader()返回系統類加載器。
findSystemClass(String name)從本地文件系統加載class文件,並生成Class對象。
使用自定義類加載器能夠實現以下功能:
執行代碼前自動驗證數字簽名;
根據用戶提供的密碼解密代碼,從而能夠實現代碼混淆器來避免反編譯class文件;
根據用戶需求來動態的加載類;
根據應用需求把其餘數據以字節碼的形式加載到應用中;
java 爲ClassLoader提供了一個實現類URLClassLoader ,該類也是系統類加載器和擴展類加載器的父類,它能夠從本地文件系統和遠程主機獲取二進制文件來加載類。
URLClassLoader的兩個構造器
URLClassLoader(URL[] urls):使用默認的父類加載器建立一個ClassLoader對象,該對象將從urls所指定的系列路徑來查詢並加載類。
URLClassLoader(URL[] urls, ClassLoader parent):使用指定的父類加載器建立。。。
一旦得到URLClassLoader對象後,就能夠調用類加載器的 loadClass()方法來加載指定的類。
ClassLoader除了用於加載類外,還能夠用於加載圖片、視頻等非類資源,也是採用雙親委派模型將加載資源的請求傳遞到頂層的Bootstrap ClassLoader,在其對應的目錄下搜索資源,若失敗才逐層返回並搜索。
相關的實例方法:
URL getResource(String name):資源名稱name是以 '/' 分隔的標識資源的路徑名稱,返回資源的 URL 對象的枚舉。
InputStream getResourceAsStream(String name):返回讀取指定資源的輸入流。
Enumeration<URL> getResources(String name)
1)class.getResource(String path):返回URL對象
path以'/'開頭時,'/'表示ClassPath,從項目的classpath下查詢資源;
path不以'/'開頭時,是今後類所在的包下查詢資源;
步驟:先遞歸在全部parent classLoader的classpath裏查找resource,若是未找到,則在JVM內置的calss loader的路徑中查找。
2)class.getClassLoader().getResource(String name):返回URL對象
The name of a resource is a '/'-separated path name that identifies the resource.
name不能以'/'開頭,指資源標識符(即相對於classpath的路徑)。通常web項目的classpath路徑爲……/webapps/appName/WEB-INF/classes/。若是資源不在此目錄下,須要用使用相對路徑作調整。
String path= MyService.class.getClassLoader().getResource("config.properties").getPath();Properties prop = new Properties();prop.load(new FileReader(path));