java虚拟机加载类_java虚拟机之类加载机制(一)
一.首先先說一下java虛擬機(jī)的生命周期:
1.執(zhí)行了system.exit();
2.程序正常執(zhí)行結(jié)束;
3.程序在執(zhí)行過程中遇到了異常或錯誤而終止;
4.由于操作系統(tǒng)出現(xiàn)錯誤而導(dǎo)致java虛擬機(jī)進(jìn)程終止;
二:ClassLoader
1.幾種類加載器:
(1).Bootstrap ClassLoader:這個主要加載JVM自身工作需要的類,是由JVM自己控制的,需要加載哪個類,怎么加載都是有JVM負(fù)責(zé)的!別人訪問不到這個類,所以這個ClassLoader是不遵守類加載規(guī)則的,因?yàn)樗鼉H僅是個工具,既沒有更高級的父加載器,也沒有子加載器! 加載源:JRE/lib/rt.jar或者是bootclasspath選項(xiàng)制定的jar;
(2).ExtClassLoader:??它是JVM的一部分,它加載的目標(biāo)是System.getProperty("java.ext.dirs");
(3).AppClassLoader:這個類跟我們平時打交道的比較多,在System.getProperty("java.class.path");的目錄下的類都可以被這個類加載,ExtClassLoader是它的父加載器。
2.JVM記載Class的兩種方式:
(1).隱式加載:通過JVM來自動加載需要的類到內(nèi)存中。如:當(dāng)我們引用某個類時,JVM解析這個類不再內(nèi)存中,就會自動把該類加載到內(nèi)存中!
(2).顯式加載:通過調(diào)用ClassLoader來加載一個類的方式。下面的例程中我將會自己下個類加載器。
3.等級加載機(jī)制(父委托機(jī)制):
通過上圖可以知道:當(dāng)一個.class文件被JVM加載的時候,JVM首先判斷是否被記載,如果被加載就結(jié)束加載過程;否則的話,就開始尋找本加載器的父類加載器,父類加載器也是先判斷是否已經(jīng)被加載,若沒有被加載&&本加載器沒有父類加載器了,就會判斷應(yīng)不應(yīng)該由我來加載,若不應(yīng)該,就會傳遞給它的子加載器,以此類推......
一開始我不明白,為什么JVM的類加載機(jī)制為什么要設(shè)計的這么麻煩!現(xiàn)在可能已經(jīng)想通了:它是為了使類能夠已正確的方式被應(yīng)該加載它的類加載器加載!
三:.class文件如何被加載到JVM中:
(1).加載:
類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個java.lang.Class對象,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。【–從本地系統(tǒng)中直接加載 ,–通過網(wǎng)絡(luò)下載.class文件 ,–從zip,jar等歸檔文件中加載.class文件, –從專有數(shù)據(jù)庫中提取.class文件, –將Java源文件動態(tài)編譯為.class文件 】
(2).驗(yàn)證:
類被加載后,就進(jìn)入連接階段。連接就是將已經(jīng)讀入到內(nèi)存的類的二進(jìn)制數(shù)據(jù)合并到虛擬機(jī)的運(yùn)行時環(huán)境中去。【類文件的結(jié)構(gòu)檢查, 語義檢查, 字節(jié)碼驗(yàn)證, 二進(jìn)制兼容性的驗(yàn)證 】
(3).準(zhǔn)備:
為類的靜態(tài)變量分配內(nèi)存(方法區(qū)),并將其初始化為默認(rèn)值!
(4).解析:
解析階段是把類的二進(jìn)制數(shù)據(jù)中的符號引用替換為直接應(yīng)用【給Java語言帶來了強(qiáng)大的動態(tài)擴(kuò)展能力】。如:
public void sayHello(){
tdd.say();
}
在本類中,包含一個對tdd的符號引用,它是由say()方法的全名和相關(guān)描述符組成。在解析階段,JVM會把這個符號引用替換為一個指針,改指針指向tdd類的say方法在方法區(qū)的內(nèi)存位置,這個指針就是直接引用!
(5).初始化:
Java程序?qū)︻惖氖褂梅绞娇煞譃閮煞N :
主動使用【創(chuàng)建類的實(shí)例 ,訪問某個類或接口的靜態(tài)變量,或者對該靜態(tài)變量賦值, 調(diào)用類的靜態(tài)方法, 反射(如Class.forName(“com.shengsiyuan.Test”)), 初始化一個類的子類 ,Java虛擬機(jī)啟動時被標(biāo)明為啟動類的類(Java Test) 】
被動使用
所有的Java虛擬機(jī)實(shí)現(xiàn)必須在每個類或接口被Java程序“首次主動使用”時才初始化他們!
在初始化階段,JVM執(zhí)行類的初始化語句,為類的靜態(tài)變量賦予初始值。在程序中,靜態(tài)變量的初始化有倆種方式:(1).在靜態(tài)變量的聲明處進(jìn)行初始化;(2)在靜態(tài)代碼中進(jìn)行初始化。
四:常見類加載錯誤分析:
(1)ClassNotFoundException:
JVM要加載指定文件的字節(jié)碼到內(nèi)存中,并滅有找到這個文件對應(yīng)的字節(jié)碼,也就是這個文件不存在!檢查當(dāng)前的classpath下面有沒有這個文件!
(2)NoClassDefFoundError:
這個有可能是你隱式加載類的時候,沒有寫全類名!NoClassDefFoundError的可能情況是:new 關(guān)鍵字,屬性引用某個類,繼承了某個接口或者類等等...
(3)UnsatisfiedLinkError:
如果不小心把JVM中的某個lib包刪掉的話,就有可能出現(xiàn)這種情況。
五:實(shí)現(xiàn)自己的類加載器:
public?class?PathClassLoader?extends?ClassLoader?{
private?byte[]?getData(String?className)?{
String?path?=?"D:/workpace/test/build/classes/";
String?namePath?=?className.replace(".",?"/");
String?classpath?=?path?+?namePath?+?".class";
try?{
InputStream?is?=?new?FileInputStream(new?File(classpath));
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?(Exception?e)?{
e.printStackTrace();
}
return?null;
}
protected?Class>?findClass(String?name)?throws?ClassNotFoundException?{
if?(name?!=?null)?{
byte[]?data?=?getData(name);
if?(data?==?null)?{
throw?new?ClassNotFoundException();
}?else?{
return?defineClass(name,?data,?0,?data.length);
}
}?else?{
return?super.loadClass(name);
}
}
public?static?void?main(String[]?args)?throws?ClassNotFoundException,
IllegalArgumentException,?IllegalAccessException,
InvocationTargetException,?InstantiationException,
SecurityException,?NoSuchMethodException?{
PathClassLoader?pathClassLoader?=?new?PathClassLoader();
Class?myClass?=?pathClassLoader.findClass("com.classloader.HelloWorld");
System.out.println(myClass);
Object?obj?=?myClass.newInstance();
Method?method?=?myClass.getMethod("say",?null);
method.invoke(obj,?null);
}
public?class?HelloWorld?{
public?void?say(){
System.out.println("hello,world");
}
}
打印結(jié)果:
class com.classloader.HelloWorld
hello,world
?
?
font
總結(jié)
以上是生活随笔為你收集整理的java虚拟机加载类_java虚拟机之类加载机制(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用c#输出正九九乘法表_用C#写九九乘法
- 下一篇: java 拼音模糊查询_java实现首字