一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

JVM加載class文件的原理機(jī)制

 昵稱10938654 2012-10-23
 Java 語言是一種具有動(dòng)態(tài)性的解釋型編程語言,當(dāng)指定程序運(yùn)行的時(shí)候, Java 虛擬機(jī)就將編譯生成的 . class 文件按照需求和一定的規(guī)則加載進(jìn)內(nèi)存,并組織成為一個(gè)完整的 Java 應(yīng)用程序。 Java 語言把每個(gè)單獨(dú)的類 Class 和接口 Implements 編譯成單獨(dú)的一個(gè) . class 文件,這些文件對(duì)于 Java 運(yùn)行環(huán)境來說就是一個(gè)個(gè)可以動(dòng)態(tài)加載的單元。正是因?yàn)?Java 的這種特性,我們可以在不重新編譯其它代碼的情況下,只編譯需要修改的單元,并把修改文件編譯后的 . class 文件放到 Java 的路徑當(dāng)中, 等到下次該 Java 虛擬機(jī)器重新激活時(shí),這個(gè)邏輯上的 Java 應(yīng)用程序就會(huì)因?yàn)榧虞d了新修改的 .class 文件,自己的功能也做了更新,這就是 Java 的動(dòng)態(tài)性。
下面用一個(gè)簡單的例子讓大家對(duì) Java 的動(dòng)態(tài)加載有一個(gè)基本的認(rèn)識(shí):

class TestClassA{

public void method(){

System.out.println("Loading ClassA");

}

}

public class ClassLoaderTest {

public static void main(String args[]){

TestClassA testClassA = new TestClassA();

testClassA.method();

}

}

編譯后輸入命令: java -verbose:class ClassLoaderTest ,執(zhí)行文件。

輸出結(jié)構(gòu)如圖 (1)


圖( 1 )

從運(yùn)行結(jié)果我們可以看到, JRE ( JavaRuntime Environment )首先加載 ClassLoaderTest 文件,然后再加載 TestClassA 文件,從而實(shí)現(xiàn)了動(dòng)態(tài)加載。



1. 預(yù)先加載與依需求加載

Java 運(yùn)行環(huán)境為了優(yōu)化系統(tǒng),提高程序的執(zhí)行速度,在 JRE 運(yùn)行的開始會(huì)將 Java 運(yùn)行所需要的基本類采用預(yù)先加載( pre-loading )的方法全部加載要內(nèi)存當(dāng)中,因?yàn)檫@些單元在 Java 程序運(yùn)行的過程當(dāng)中經(jīng)常要使用的,主要包括 JRE 的 rt.jar 文件里面所有的 .class 文件。

當(dāng) java.exe 虛擬機(jī)開始運(yùn)行以后,它會(huì)找到安裝在機(jī)器上的 JRE 環(huán)境,然后把控制權(quán)交給 JRE , JRE 的類加載器會(huì)將 lib 目錄下的 rt.jar 基礎(chǔ)類別文件庫加載進(jìn)內(nèi)存,這些文件是 Java 程序執(zhí)行所必須的,所以系統(tǒng)在開始就將這些文件加載,避免以后的多次 IO 操作,從而提高程序執(zhí)行效率。

圖( 2 )我們可以看到多個(gè)基礎(chǔ)類被加載, java.lang.Object,java.io.Serializable 等等。


圖( 2 )

相對(duì)于預(yù)先加載,我們?cè)诔绦蛑行枰褂米约憾x的類的時(shí)候就要使用依需求加載方法( load-on-demand ),就是在 Java 程序需要用到的時(shí)候再加載,以減少內(nèi)存的消耗,因?yàn)?Java 語言的設(shè)計(jì)初衷就是面向嵌入式領(lǐng)域的。

在這里還有一點(diǎn)需要說明的是, JRE 的依需求加載究竟是在什么時(shí)候把類加載進(jìn)入內(nèi)部的呢?

我們?cè)诙x一個(gè)類實(shí)例的時(shí)候,比如 TestClassA testClassA ,這個(gè)時(shí)候 testClassA 的值為 null ,也就是說還沒有初始化,沒有調(diào)用 TestClassA 的構(gòu)造函數(shù),只有當(dāng)執(zhí)行 testClassA = new TestClassA() 以后, JRE 才正真把 TestClassA 加載進(jìn)來。



2. 隱式加載和顯示加載

Java 的加載方式分為隱式加載( implicit )和顯示加載( explicit ),上面的例子中就是用的隱式加載的方式。所謂隱式加載就是我們?cè)诔绦蛑杏?new 關(guān)鍵字來定義一個(gè)實(shí)例變量, JRE 在執(zhí)行到 new 關(guān)鍵字的時(shí)候就會(huì)把對(duì)應(yīng)的實(shí)例類加載進(jìn)入內(nèi)存。隱式加載的方法很常見,用的也很多, JRE 系統(tǒng)在后臺(tái)自動(dòng)的幫助用戶加載,減少了用戶的工作量,也增加了系統(tǒng)的安全性和程序的可讀性。

相對(duì)于隱式加載的就是我們不經(jīng)常用到的顯示加載。所謂顯示加載就是有程序員自己寫程序把需要的類加載到內(nèi)存當(dāng)中,下面我們看一段程序:

class TestClass{

public void method(){

System.out.println("TestClass-method");

}

}



public class CLTest {

public static void main(String args[]) {

try{

Class c = Class.forName("TestClass");

TestClass object = (TestClass)c.newInstance();

object.method();

}catch(Exception e){

e.printStackTrace();

}

}

}

我們通過 Class 類的 forName (String s) 方法把自定義類 TestClass 加載進(jìn)來,并通過 newInstance ()方法把實(shí)例初始化。事實(shí)上 Class 類還很多的功能,這里就不細(xì)講了,有興趣的可以參考 JDK 文檔。

Class 的 forName() 方法還有另外一種形式: Class forName(String s, boolean flag, ClassLoader classloader) , s 表示需要加載類的名稱, flag 表示在調(diào)用該函數(shù)加載類的時(shí)候是否初始化靜態(tài)區(qū), classloader 表示加載該類所需的加載器。

forName (String s) 是默認(rèn)通過 ClassLoader.getCallerClassLoader() 調(diào)用類加載器的,但是該方法是私有方法,我們無法調(diào)用,如果我們想使用 Class forName(String s, boolean flag, ClassLoader classloader) 來加載類的話,就必須要指定類加載器,可以通過如下的方式來實(shí)現(xiàn):

Test test = new Test();//Test 類為自定義的一個(gè)測(cè)試類;

ClassLoader cl = test. getClass().getClassLoader();

// 獲取 test 的類裝載器;

Class c = Class.forName("TestClass", true, cl);

因?yàn)橐粋€(gè)類要加載就必需要有加載器,這里我們是通過獲取加載 Test 類的加載器 cl 當(dāng)作加載 TestClass 的類加載器來實(shí)現(xiàn)加載的。



3. 自定義類加載機(jī)制

之前我們都是調(diào)用系統(tǒng)的類加載器來實(shí)現(xiàn)加載的,其實(shí)我們是可以自己定義類加載器的。利用 Java 提供的 java.net.URLClassLoader 類就可以實(shí)現(xiàn)。下面我們看一段范例:

try{

URL url = new URL("file:/d:/test/lib/");

URLClassLoader urlCL = new URLClassLoader(new URL[]{url});

Class c = urlCL.loadClass("TestClassA");

TestClassA object = (TestClassA)c.newInstance();

object.method();

}catch(Exception e){

e.printStackTrace();

}

我們通過自定義的類加載器實(shí)現(xiàn)了 TestClassA 類的加載并調(diào)用 method ()方法。分析一下這個(gè)程序:首先定義 URL 指定類加載器從何處加載類, URL 可以指向網(wǎng)際網(wǎng)絡(luò)上的任何位置,也可以指向我們計(jì)算機(jī)里的文件系統(tǒng) ( 包含 JAR 文件 ) 。上述范例當(dāng)中我們從 file:/d:/test/lib/ 處尋找類;然后定義 URLClassLoader 來加載所需的類,最后即可使用該實(shí)例了。



4. 類加載器的階層體系

討論了這么多以后,接下來我們仔細(xì)研究一下 Java 的類加載器的工作原理:

當(dāng)執(zhí)行 java ***.class 的時(shí)候, java.exe 會(huì)幫助我們找到 JRE ,接著找到位于 JRE 內(nèi)部的 jvm.dll ,這才是真正的 Java 虛擬機(jī)器 , 最后加載動(dòng)態(tài)庫,激活 Java 虛擬機(jī)器。虛擬機(jī)器激活以后,會(huì)先做一些初始化的動(dòng)作,比如說讀取系統(tǒng)參數(shù)等。一旦初始化動(dòng)作完成之后,就會(huì)產(chǎn)生第一個(gè)類加載器―― Bootstrap Loader , Bootstrap Loader 是由 C++ 所撰寫而成,這個(gè) Bootstrap Loader 所做的初始工作中,除了一些基本的初始化動(dòng)作之外,最重要的就是加載 Launcher.java 之中的 ExtClassLoader ,并設(shè)定其 Parent 為 null ,代表其父加載器為 BootstrapLoader 。然后 Bootstrap Loader 再要求加載 Launcher.java 之中的 AppClassLoader ,并設(shè)定其 Parent 為之前產(chǎn)生的 ExtClassLoader 實(shí)體。這兩個(gè)加載器都是以靜態(tài)類的形式存在的。這里要請(qǐng)大家注意的是, Launcher$ExtClassLoader.class 與 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加載,所以 Parent 和由哪個(gè)類加載器加載沒有關(guān)系。

下面的圖形可以表示三者之間的關(guān)系:

父類

父類

載入

載入

BootstrapLoader

PARENT

AppClassLoader

PARENT

ExtClassLoader

這三個(gè)加載器就構(gòu)成我們的 Java 類加載體系。他們分別從以下的路徑尋找程序所需要的類:

BootstrapLoader : sun.boot.class.path

ExtClassLoader: java.ext.dirs

AppClassLoader: java.class.path

這三個(gè)系統(tǒng)參量可以通過 System.getProperty() 函數(shù)得到具體對(duì)應(yīng)的路徑。大家可以自己編程實(shí)現(xiàn)查看具體的路徑。



5. 總結(jié)

了解 Java 的類加載機(jī)制對(duì)我們熟練靈活運(yùn)用 Java 語言,提高程序的運(yùn)行效率有著非常重要的作用,知其然也要知其所以然,這樣才能從整體提高程序的質(zhì)量。


以上是個(gè)人為了畢業(yè)要發(fā)表的一篇論文,沒有什么深度,下面再繼續(xù)討論一點(diǎn)關(guān)于ClassLoader的一定東東:

public class ClassLoaderTest1{
private ClassLoaderTest2 test = null;
public ClassLoaderTest1(){
test = new ClassLoaderTest2();
}
public void method(){
System.out.println("Loading ClassA");
}
}


class ClassLoaderTest2{
public ClassLoaderTest2(){

}
public void method(){
System.out.println("Loading ClassA");
}
}

測(cè)試程序:
URL url = null;
try {
url = new URL("file:/E:/JAVA/MyProject/string/");
} catch (MalformedURLException e) {
e.printStackTrace();
}
URLClassLoader cl = new URLClassLoader(new URL[]{url});
URLClassLoader cl1 = new URLClassLoader(new URL[]{url});
try {
Class tempClass = cl.loadClass("ClassLoaderTest1");
Class tempClass2 = cl.loadClass("ClassLoaderTest2");
Object test = tempClass.newInstance();
System.out.println(tempClass.getClassLoader());
System.out.println(tempClass2.getClassLoader());
} catch (Exception e) {
e.printStackTrace();
}

當(dāng)ClassLoaderTest1,ClassLoaderTest2在當(dāng)前目錄和E:/JAVA/MyProject/string/都存在的時(shí)候輸出為sun.misc.Launcher$AppClassLoader@1050169
sun.misc.Launcher$AppClassLoader@1050169
即都是被AppClassLoader加載的, 即使在E:/JAVA/MyProject/string/下面也存在.

當(dāng)ClassLoaderTest1,ClassLoaderTest2只在E:/JAVA/MyProject/string/下存在的時(shí)候輸出為
java.net.URLClassLoader@480457
java.net.URLClassLoader@1a7bf11
即都是被自定義的加載器加載的,并且也可以O(shè)bject test = tempClass.newInstance();

下面一的是最關(guān)鍵的,因?yàn)镃lassLoaderTest1需要用到ClassLoaderTest2,如果ClassLoaderTest2被AppClassLoader加載,而ClassLoaderTest1是被自定義的類加載器加載,就會(huì)出現(xiàn)如下錯(cuò)誤:

java.lang.IllegalAccessError: tried to access class ClassLoaderTest2 from class ClassLoaderTest1
at ClassLoaderTest1. <init>(ClassLoaderTest1.java:6)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
at java.lang.Class.newInstance0(Class.java:308)
at java.lang.Class.newInstance(Class.java:261)
at ClassLoaderTest.main(ClassLoaderTest.java:43)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    日本高清视频在线观看不卡| 日本高清不卡在线一区| 日韩免费午夜福利视频| 手机在线不卡国产视频| 乱女午夜精品一区二区三区| 毛片在线观看免费日韩| 欧美日韩乱一区二区三区| 国产午夜免费在线视频| 国产亚洲精品久久久优势| 麻豆视频传媒入口在线看| 一个人的久久精彩视频| 激情国产白嫩美女在线观看| 欧美日韩在线第一页日韩| 伊人国产精选免费观看在线视频| 日韩一区二区三区在线日| 老司机精品福利视频在线播放| 国产精品成人免费精品自在线观看 | 99热九九热这里只有精品| 亚洲国产精品久久琪琪| 国产欧美日韩精品一区二| 国产精品二区三区免费播放心| 草草视频精品在线观看| 国产又粗又爽又猛又黄的| av中文字幕一区二区三区在线| 黄片免费播放一区二区| 欧美色欧美亚洲日在线| 日本欧美在线一区二区三区| 午夜精品国产精品久久久| 好东西一起分享老鸭窝| 国产亚洲精品俞拍视频福利区| 国产女性精品一区二区三区| 亚洲视频一级二级三级| 三级高清有码在线观看| 国产亚洲二区精品美女久久| 欧美成人精品一区二区久久| 亚洲午夜福利视频在线| 日本午夜免费观看视频| 国产精品香蕉一级免费| 亚洲国产成人久久99精品| 国产一区二区不卡在线播放| 日韩国产亚洲欧美激情|