亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

瀏覽:36日期:2022-08-16 13:54:20
JVM自帶的類(lèi)加載器:

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

其關(guān)系如下:

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

其中,類(lèi)加載器在加載類(lèi)的時(shí)候是使用了所謂的“父委托”機(jī)制。其中,除了根類(lèi)加載器以外,其他的類(lèi)加載器都有且只有一個(gè)父類(lèi)加載器。

關(guān)于父委托機(jī)制的說(shuō)明:

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

當(dāng)生成 一個(gè)自定義的類(lèi)加載器實(shí)例時(shí),如果沒(méi)有指定它的父加載器,那么系統(tǒng)類(lèi)加載器將成為該類(lèi)加載器的父類(lèi)加載器

下面,自定義類(lèi)加載器。自定義的類(lèi)加載器必須繼承java.lang.ClassLoader類(lèi)

import java.io.*;public class MyClassLoader extends ClassLoader { private String name; //類(lèi)加載器的名字 private String path; //加載類(lèi)的路徑 private final String fileType = '.class'; //class文件的擴(kuò)展名 public MyClassLoader(String name){ super(); //讓系統(tǒng)類(lèi)加載器成為該類(lèi)加載器的父 類(lèi)加載器,該句可省略不寫(xiě) this.name = name; } public MyClassLoader(ClassLoader parent,String name){ super(parent); //顯示指定該類(lèi)加載器的父 類(lèi)加載器 this.name = name; } @Override public String toString() { return this.name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } //實(shí)現(xiàn)自定義的類(lèi)加載器必須重寫(xiě)findClass方法,否則ClassLoader類(lèi)中的findClass()方法是拋出了異常 @Override public Class findClass(String name)throws ClassNotFoundException{ byte[] data = this.loadClassData(name); return this.defineClass(name,data,0,data.length); } private byte[] loadClassData(String name){ InputStream is = null; byte[] data = null; ByteArrayOutputStream baos = null; try { this.name = this.name.replace('.',''); //com.dream.it---->comdreamit is = new FileInputStream(new File(path + name + fileType)); int ch; while(-1 != (ch = is.read())){baos.write(ch); //將數(shù)據(jù)寫(xiě)入到字節(jié)數(shù)組輸出流對(duì)象中去 } data = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); }finally { try {is.close();baos.close(); } catch (IOException e) {e.printStackTrace(); } } return data; } public static void main(String[] args) throws Exception { MyClassLoader loader1 = new MyClassLoader('loader1'); loader1.setPath('d:/myapp/serverlib/'); MyClassLoader loader2 = new MyClassLoader(loader1,'loader2'); //loader1作為loader2的父 類(lèi)加載器 loader2.setPath('d:/myapp/clientlib'); MyClassLoader loader3 = new MyClassLoader(null,'loader3');//父類(lèi)加載器為null,表明其父類(lèi)加載器為根類(lèi)加載器 loader3.setPath('d:/myapp/otherlib'); test(loader2); test(loader3); } public static void test(ClassLoader cl) throws Exception { Class clazz = cl.loadClass('Sample'); Object object = clazz.newInstance(); }}附上findClass()方法的JDK說(shuō)明

protected Class<?> findClass(String name) throws ClassNotFoundExceptionFinds the class with the specified binary name. This method should be overridden by class loaderimplementations that follow the delegation model for loading classes, and will be invoked by the loadClass method after checking the parent classloader for the requested class. The default implementation throws a ClassNotFoundException.

大致說(shuō)明一下意思:通過(guò)指定的name來(lái)查找類(lèi)。該方法應(yīng)該被類(lèi)加載器的實(shí)現(xiàn)類(lèi)重寫(xiě),從而能夠保證在加載類(lèi)的時(shí)候可以遵循委托機(jī)制模型。在loadClass()方法(該方法是由JVM調(diào)用的)中,檢查其父類(lèi)加載器之后,該方法再被調(diào)用去加載請(qǐng)求的類(lèi)。默認(rèn)該方法的實(shí)現(xiàn)是拋出了一個(gè)ClassNotFoundException異常。

其實(shí),所謂的加載類(lèi),無(wú)非就是讀取.class文件到內(nèi)存中,所以在findClass()方法中,loadClassData()方法用于讀取.class文件的數(shù)據(jù),并返回一個(gè)字節(jié)數(shù)組。然后利用ClassLoader類(lèi)的defineClass()方法將字節(jié)數(shù)組轉(zhuǎn)換為Class對(duì)象。

上述自定義的類(lèi)加載器loader1,loader2,loader3及JVM自帶的類(lèi)加載器之間的關(guān)系如下:

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

對(duì)于各個(gè)類(lèi)加載器,系統(tǒng)的類(lèi)加載器是從環(huán)境變量classpath中讀取.class文件實(shí)現(xiàn)類(lèi)的加載;loader1是從目錄d:/myapp/serverlib/下讀取.class文件;loader2是從目錄d:/myapp/clientlib/下讀取.class文件,loader3是從目錄d:/myapp/otherlib/下讀取.class文件

執(zhí)行結(jié)果:

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

此處我們分析一下出現(xiàn)這種執(zhí)行結(jié)果的原因:

當(dāng)執(zhí)行l(wèi)oader2.loadClass(“Sample”)時(shí)先由它上層的所有父類(lèi)加載器嘗試加載Sample類(lèi)。

loader1從D:myappserverliv目錄下成功加載了Sample類(lèi),所以loader1是Sample類(lèi)的定義類(lèi)加載器,loader1和loader2是Sample類(lèi)的初始類(lèi)加載器。

當(dāng)執(zhí)行l(wèi)oader3.loadClass(“Sample”)時(shí),先由它上層的所有父類(lèi)加載器嘗試加載Sample類(lèi)。

loader3的父加載器為根類(lèi)加載器,它無(wú)法加載Sample類(lèi),接著loader3從D:myappotherlib目錄下成功加載Sample類(lèi),所以loader3是Sample類(lèi)的定義類(lèi)加載器及初始類(lèi)加載器。

在Sample類(lèi)中主動(dòng)使用了Dog類(lèi)(new Dog()),當(dāng)執(zhí)行Sample類(lèi)的構(gòu)造方法中的new Dog()語(yǔ)句時(shí),JVM需要先加載Dog類(lèi),到底用哪個(gè)類(lèi)加載器家在呢?

從上述的打印結(jié)果中可以看出,加載Sample類(lèi)的loader1還加載了Dog類(lèi),JVM會(huì)用Sample類(lèi)的定義類(lèi)加載器去加載Dog類(lèi),加載過(guò)程中也同樣采用了父親委托機(jī)制。

為了驗(yàn)證這一點(diǎn),可以吧D:myappserverlib目錄下Dog.class文件刪除,然后在D:myappsyslib目錄下存放一個(gè)Dog.class文件,此時(shí)打印結(jié)果如下:

Sample:loader1Dog:sun.misc.Launcher$AppClassLoader@1b84c92Sample:loader3Dog:loader3

由此可見(jiàn),當(dāng)由loader1加載的Sample類(lèi)首次主動(dòng)使用Dog類(lèi)時(shí),Dog類(lèi)由系統(tǒng)類(lèi)加載器加載,如果把D:myappserverlib和D:myappsyslib目錄下的Dog.class文件都刪除,然后在D:myappclient目錄下存放一個(gè)Dog.class文件。

此時(shí)文件結(jié)構(gòu)如下圖所示:

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

當(dāng)Loader1加載Sample類(lèi)首次主動(dòng)使用Dog類(lèi)時(shí),由于loader1及其父類(lèi)加載器都無(wú)法加載Dog類(lèi),因此test(loader2)會(huì)拋出ClassNotFoundExcption.

這又是因?yàn)槭裁丛蚰兀?/p>

這又牽扯到命名空間的問(wèn)題。

同一個(gè)命名空間內(nèi)的類(lèi)時(shí)相互可見(jiàn)的。

子加載器的命名空間包含所有父類(lèi)加載器的命名空間,因此由子加載器加載的類(lèi)能看見(jiàn)父類(lèi)加載器加載的類(lèi)。例如系統(tǒng)類(lèi)加載器加載的類(lèi)能看見(jiàn)根類(lèi)加載器加載的類(lèi)。由父加載器加載的類(lèi)不能看見(jiàn)子加載器加載的類(lèi)。

如果兩個(gè)加載器之間沒(méi)有直接或間接的父子關(guān)系,那么它們各自加載的類(lèi)相互不可見(jiàn)。

對(duì)于上述問(wèn)題,loader1可以加載Sample類(lèi),而Dog類(lèi)只能由loader2加載Dog類(lèi),loader1是Loader2的父類(lèi)加載器,父加載器loader1加載的類(lèi)Sample不能看見(jiàn)子加載器loader2加載的類(lèi)Dog,所以會(huì)拋出異常。

對(duì)于上述實(shí)例中的main方法,我們不調(diào)用test方法,換成如下代碼

Class clazz = loader1.loadClass('Sample');Object obj = clazz.newInstance();Sample sample = (Sample)obj;System.out.println(sample.v1);

MyClassLoader類(lèi)由系統(tǒng)類(lèi)加載器加載,而Sample類(lèi)由loader1類(lèi)加載器加載,所以MyClassLoader類(lèi)看不見(jiàn)Sample類(lèi)。在MyClassLoader類(lèi)的main方法中使用Sample類(lèi),會(huì)導(dǎo)致NoClassFoundError錯(cuò)誤。

當(dāng)兩個(gè)不同命名空間內(nèi)的類(lèi)相互不可見(jiàn)時(shí),可采用Java反射機(jī)制來(lái)訪問(wèn)對(duì)象實(shí)例的屬性和方法。

將上述代碼修改:

Class clazz = loader1.loadClass('Sample');Object obj = clazz.newInstance();Field field = clazz.getField('v1');int v1 = field.getInt(obj);System.out.println(v1);

此時(shí),可以獲取到對(duì)象中的v1屬性值。利用反射機(jī)制,我們可以跨越這種命名空間的限制。

補(bǔ)充:

命名空間:

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

運(yùn)行時(shí)包:

淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 国产精品久久久亚洲第一牛牛 | 欧美操片在线观看 | 久久99精品久久久久久野外 | 亚洲国产精品一区二区三区久久 | 久久综合精品国产一区二区三区 | 99久久一区 | 亚洲国产麻豆 | 免费一级a毛片夜夜看 | 18p爽视频在线观看免费 | 国产日韩欧美在线观看播放 | 亚洲精品午夜级久久久久 | 亚洲成人免费视频 | 午夜资源在线 | 欧美色欧美亚洲高清在线视频 | aaa免费看| 免费一区视频 | 国产精品女上位在线观看 | 亚洲国产最新 | 91av视频免费在线观看 | 国产xxxx做受欧美88xx00tube | 免费人成网站在线播放 | 美女白丝超短裙被输出动态图 | 91短视频在线高清hd | 国产福利91精品一区二区 | 口国产成人高清在线播放 | 精品一区二区三区自拍图片区 | 在线91精品亚洲网站精品成人 | 妞干网在线视频 | 中文国产成人精品久久久 | 日本一区二区三区有限公司 | 美女一区二区在线观看 | 欧美精品免费线视频观看视频 | 国产乱人乱精一区二区视频密 | 亚洲三级毛片 | 精品乱人伦一区二区三区 | 亚洲国产第一区二区三区 | 亚洲国产精品视频在线观看 | h国产| 亚洲一区二区三区麻豆 | 日韩欧美中文 | 亚洲 欧洲 另类 综合 自拍 |