這篇文章將為大家詳細(xì)講解有關(guān)什么是Java動(dòng)態(tài)類加載和重新加載,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

Java中可以在運(yùn)行時(shí)加載和重新加載類,雖然并不像我們想像中那么簡(jiǎn)單。本文將解釋何時(shí)、怎樣在Java中加載、重新加載類。
你可以爭(zhēng)論動(dòng)態(tài)加載類是Java反射的一部分還是Java核心的一部分。不管怎樣,我把它放在了Java反射中,因?yàn)闆](méi)有更好的地方放置它。
Java程序的所有類都是使用 java.lang.ClassLoader的一些子類加載的。因此,動(dòng)態(tài)加載類也必須使用 java.lang.ClassLoader的子類。
當(dāng)一個(gè)類加載,它所引用的類也會(huì)被加載。類加載模式是遞歸加載的,直到所有需要的類加載完畢。這可能并不是應(yīng)用程序的所有類。未被引用的類在引用前不會(huì)被加載。
類加載在Java中被組織成層級(jí)。當(dāng)你創(chuàng)建一個(gè)獨(dú)立的ClassLoader,你必須提供一個(gè)父級(jí)ClassLoader。如果ClassLoader被請(qǐng)求加載一個(gè)類,它會(huì)請(qǐng)求它的父級(jí)ClassLoader去加載它。如果父級(jí)類加載器找不到這個(gè)類,子類加載器會(huì)嘗試自加載。
類加載類加載器加載類的步驟如下:
檢查該類是否已被加載
如類未加載,請(qǐng)求父類加載器加載它
如父類加載器不能加載該類,嘗試使用當(dāng)前類加載器加載它
當(dāng)你實(shí)現(xiàn)一個(gè)能夠重載類的類加載器時(shí),你需要從這個(gè)序列中偏離一點(diǎn)。不應(yīng)請(qǐng)求父類加載程序加載要重裝的類。稍后再談。
動(dòng)態(tài)類加載動(dòng)態(tài)加載類非常簡(jiǎn)單。所有你需要做的是獲得一個(gè)ClassLoader并調(diào)用它的loadClass()方法。示例如下:
public class MainClass {
public static void main(String[] args){
ClassLoader classLoader = MainClass.class.getClassLoader();
try {
Class aClass = classLoader.loadClass("com.jenkov.MyClass");
System.out.println("aClass.getName() = " + aClass.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}動(dòng)態(tài)類重新加載動(dòng)態(tài)類重新加載有一些挑戰(zhàn)。Java內(nèi)建的類加載器在加載類之前總會(huì)檢查類是否已被加載。因此,使用Java的內(nèi)置類加載器不可能重新加載類。重新加載一個(gè)類你必須實(shí)現(xiàn)自己的ClassLoader子類。
即使使用類加載器的自定義子類,也會(huì)遇到挑戰(zhàn)。所有已被加載的類都需要被鏈接。這個(gè)方法是final的,因此不能被你的ClassLoader子類重載。resolve()方法不允許ClassLoader實(shí)例鏈接一個(gè)類2次。因此,每當(dāng)你需要重新加載類時(shí),你必須重新創(chuàng)建一個(gè)ClassLoader類的實(shí)例。這不是不可能的,但必須知道何時(shí)設(shè)計(jì)類重新加載。
如上文述,不能使用加載指定類的ClassLoader重新加載這個(gè)類。因此,必須使用不同的ClassLoader加載這個(gè)類。但是,這會(huì)帶來(lái)新的問(wèn)題。
Java程序中加載的每一個(gè)類都以其全限定名(包名+類名)標(biāo)識(shí),并且由ClassLoader實(shí)例加載。這意味著,類MyObject由類加載器A加載,是和由類加載器B加載的同一個(gè)類MyObject不相同。模擬代碼如下:
MyObject object = (MyObject)
myClassReloadingFactory.newInstance("com.jenkov.MyObject");注意,類MyObject在代碼中是如何引用的,是作為object類型的變量。這導(dǎo)致MyObject類被已加載過(guò)這個(gè)類的駐留代碼的類加載器加載。
如果myClassReloadingFactory對(duì)象工廠使用與駐留代碼不同的類加載器加載MyObject,你不能強(qiáng)制轉(zhuǎn)換重新加載的Object類型的變量MyObject為MyObject類型。因?yàn)檫@兩個(gè)MyObject由不同的類加載器加載,他們被視為不同的類,盡管他們擁有相同的全限定名。嘗試強(qiáng)轉(zhuǎn)一個(gè)object的類為另一個(gè)類的引用將拋出ClassCastException。
有可能繞過(guò)這個(gè)限制,但是你必須用兩種方式來(lái)改變你的代碼:
使用接口作為變量類型,并且只重新加載實(shí)現(xiàn)類
使用超類作為變量類型,并且只重新加載子類
這里是示例代碼:
MyObjectInterface object = (MyObjectInterface)
myClassReloadingFactory.newInstance("com.jenkov.MyObject");MyObjectSuperclass object = (MyObjectSuperclass)
myClassReloadingFactory.newInstance("com.jenkov.MyObject");如果變量類型是接口或超類,上面的代碼都會(huì)正常運(yùn)行,接口或超類在重新加載實(shí)現(xiàn)或子類時(shí)不會(huì)被重新加載。
為了上面代碼的正常運(yùn)行,你當(dāng)然需要實(shí)現(xiàn)自己的類加載器,讓接口或超類由其父類加載。當(dāng)你的類加載器被請(qǐng)求加載MyObject時(shí),它也會(huì)被請(qǐng)求加載MyObjectInterface接口或者M(jìn)yObjectSuperclass類,因?yàn)樗鼈儽籑yObject類在內(nèi)部引用。你的類加載器必須把類加載委派給相同的類加載器,即加載了接口或超類的類加載器。
上文包含了很多內(nèi)容。讓我們看一下簡(jiǎn)單的示例。下面是一個(gè)簡(jiǎn)單的ClassLoader子類。注意它如何將類加載委托給它的父類,除了它想要重裝的一個(gè)類之外。如果類加載被委派給了它的父類,它以后將不能被重新加載。記住,一個(gè)類只能被同一個(gè)ClassLoader實(shí)例加載。
如前所述,這只是一個(gè)示例,它顯示了類加載器的行為的基本知識(shí)。這并不是一個(gè)你的類加載器的生產(chǎn)就緒的模板。你的類加載器可能并不僅限于一個(gè)類,可能是一個(gè)你想要重新加載的類的集合。此外,你也不能硬編碼class path。
public class MyClassLoader extends ClassLoader{
public MyClassLoader(ClassLoader parent) {
super(parent);
}
public Class loadClass(String name) throws ClassNotFoundException {
if(!"reflection.MyObject".equals(name))
return super.loadClass(name);
try {
String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +
"classes/reflection/MyObject.class";
URL myUrl = new URL(url);
URLConnection connection = myUrl.openConnection();
InputStream input = connection.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = input.read();
while(data != -1){
buffer.write(data);
data = input.read();
}
input.close();
byte[] classData = buffer.toByteArray();
return defineClass("reflection.MyObject",
classData, 0, classData.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}下面是使用MyClassLoader的示例:
public static void main(String[] args) throws
ClassNotFoundException,
IllegalAccessException,
InstantiationException {
ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
Class myObjectClass = classLoader.loadClass("reflection.MyObject");
AnInterface2 object1 =
(AnInterface2) myObjectClass.newInstance();
MyObjectSuperClass object2 =
(MyObjectSuperClass) myObjectClass.newInstance();
//create new class loader so classes can be reloaded.
classLoader = new MyClassLoader(parentClassLoader);
myObjectClass = classLoader.loadClass("reflection.MyObject");
object1 = (AnInterface2) myObjectClass.newInstance();
object2 = (MyObjectSuperClass) myObjectClass.newInstance();
}reflection.MyObject類是由自定義類加載器加載的。注意,它是如何繼承一個(gè)超類、實(shí)現(xiàn)一個(gè)接口的。這只是為了這個(gè)例子。在你的代碼中,只需要兩個(gè)中的一個(gè),繼承超類或?qū)崿F(xiàn)接口。
public class MyObject extends MyObjectSuperClass implements AnInterface2{
//... body of class ... override superclass methods
// or implement interface methods
}關(guān)于什么是Java動(dòng)態(tài)類加載和重新加載就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
網(wǎng)站題目:什么是Java動(dòng)態(tài)類加載和重新加載-創(chuàng)新互聯(lián)
標(biāo)題路徑:http://chinadenli.net/article16/cddsdg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化、用戶體驗(yàn)、軟件開(kāi)發(fā)、虛擬主機(jī)、定制網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容