成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java反射-動(dòng)態(tài)類加載和重新加載

nodejh / 3143人閱讀

摘要:示例如下動(dòng)態(tài)類重新加載動(dòng)態(tài)類重新加載有一些挑戰(zhàn)。為了上面代碼的正常運(yùn)行,你當(dāng)然需要實(shí)現(xiàn)自己的類加載器,讓接口或超類由其父類加載。

Java中可以在運(yùn)行時(shí)加載和重新加載類,雖然并不像我們想像中那么簡(jiǎn)單。本文將解釋何時(shí)、怎樣在Java中加載、重新加載類。
你可以爭(zhēng)論動(dòng)態(tài)加載類是Java反射的一部分還是Java核心的一部分。不管怎樣,我把它放在了Java反射中,因?yàn)闆]有更好的地方放置它。

類加載器

Java程序的所有類都是使用 java.lang.ClassLoader的一些子類加載的。因此,動(dòng)態(tài)加載類也必須使用 java.lang.ClassLoader的子類。
當(dāng)一個(gè)類加載,它所引用的類也會(huì)被加載。類加載模式是遞歸加載的,直到所有需要的類加載完畢。這可能并不是應(yīng)用程序的所有類。未被引用的類在引用前不會(huì)被加載。

類加載層級(jí)結(jié)構(gòu)

類加載在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ì)類重新加載。

類重載代碼設(shè)計(jì)

如上文述,不能使用加載指定類的ClassLoader重新加載這個(gè)類。因此,必須使用不同的ClassLoader加載這個(gè)類。但是,這會(huì)帶來新的問題。
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類被已加載過這個(gè)類的駐留代碼的類加載器加載。
如果myClassReloadingFactory對(duì)象工廠使用與駐留代碼不同的類加載器加載MyObject,你不能強(qiáng)制轉(zhuǎn)換重新加載的Object類型的變量MyObjectMyObject類型。因?yàn)檫@兩個(gè)MyObject由不同的類加載器加載,他們被視為不同的類,盡管他們擁有相同的全限定名。嘗試強(qiáng)轉(zhuǎn)一個(gè)object的類為另一個(gè)類的引用將拋出ClassCastException
有可能繞過這個(gè)限制,但是你必須用兩種方式來改變你的代碼:

使用接口作為變量類型,并且只重新加載實(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接口或者MyObjectSuperclass類,因?yàn)樗鼈儽?b>MyObject類在內(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
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71703.html

相關(guān)文章

  • Java動(dòng)態(tài)編程初探

    摘要:動(dòng)態(tài)編程使用場(chǎng)景通過配置生成代碼,減少重復(fù)編碼,降低維護(hù)成本。動(dòng)態(tài)生成字節(jié)碼操作字節(jié)碼的工具有,其中有兩個(gè)比較流行的,一個(gè)是,一個(gè)是。 作者簡(jiǎn)介 傳恒,一個(gè)喜歡攝影和旅游的軟件工程師,先后從事餓了么物流蜂鳥自配送和蜂鳥眾包的開發(fā),現(xiàn)在轉(zhuǎn)戰(zhàn) Java,目前負(fù)責(zé)物流策略組分流相關(guān)業(yè)務(wù)的開發(fā)。 什么是動(dòng)態(tài)編程 動(dòng)態(tài)編程是相對(duì)于靜態(tài)編程而言的,平時(shí)我們討論比較多的靜態(tài)編程語言例如Java, 與動(dòng)態(tài)...

    趙連江 評(píng)論0 收藏0
  • Java 反射教程

    摘要:反射非常強(qiáng)大和有用。另外,反射可以用在映射結(jié)果集的列名到對(duì)象的方法。本教程將深入介紹反射。本教程還將清除一些關(guān)于范型信息在運(yùn)行時(shí)可用性的認(rèn)知混淆。類對(duì)象使用反射時(shí),起點(diǎn)通常是需要使用反射檢視的類的對(duì)象。 Java反射可以在運(yùn)行時(shí)檢視類、接口、屬性和方法,而無需在編譯時(shí)知道類名、方法名等等。它也同樣使用反射支持實(shí)例化新的對(duì)象、調(diào)用方法和get/set屬性值。 Java反射非常強(qiáng)大和有用...

    klivitamJ 評(píng)論0 收藏0
  • Java動(dòng)態(tài)性(2) - 之反射機(jī)制(Reflection)

    摘要:的動(dòng)態(tài)性反射機(jī)制動(dòng)態(tài)編譯動(dòng)態(tài)執(zhí)行代碼動(dòng)態(tài)字節(jié)碼操作動(dòng)態(tài)語言程序運(yùn)行時(shí)可以改變程序得結(jié)構(gòu)或變量類型典型語言等如下代碼不是動(dòng)態(tài)語言但有一定的動(dòng)態(tài)性我們可以利用反射機(jī)制字節(jié)碼操作獲得類似動(dòng)態(tài)語言的特性的動(dòng)態(tài)性讓編程的時(shí)候更加靈活反射機(jī)制反射機(jī)制指 1.Java的動(dòng)態(tài)性 反射機(jī)制 動(dòng)態(tài)編譯 動(dòng)態(tài)執(zhí)行JavaScript代碼 動(dòng)態(tài)字節(jié)碼操作 2.動(dòng)態(tài)語言 程序運(yùn)行時(shí),可以改變程序得結(jié)構(gòu)或變量...

    妤鋒シ 評(píng)論0 收藏0
  • 反射機(jī)制與原理筆記

    反射機(jī)制與原理筆記 聲明 文章均為本人技術(shù)筆記,轉(zhuǎn)載請(qǐng)注明出處https://segmentfault.com/u/yzwall 反射機(jī)制 反射:當(dāng)程序無法獲知對(duì)象類型時(shí),在運(yùn)行期間動(dòng)態(tài)獲取類的所有屬性和方法,這種動(dòng)態(tài)獲取類信息和動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為反射機(jī)制;反射機(jī)制實(shí)現(xiàn):Class類與java.lang.reflect類庫一起實(shí)現(xiàn)機(jī)制,java.lang.reflect類庫包含F(xiàn)ield...

    fobnn 評(píng)論0 收藏0
  • Java反射詳細(xì)介紹

    摘要:通過反射獲取帶參無返回值成員方法并使用設(shè)置安全檢查,訪問私有構(gòu)造函數(shù)必須創(chuàng)建實(shí)例這種不行,注意和方法需要傳遞參數(shù)測(cè)試復(fù)制這個(gè)功能獲取私有方法,同樣注意和的區(qū)別賦予訪問權(quán)限調(diào)用方法。 反射 目錄介紹 1.反射概述 1.1 反射概述 1.2 獲取class文件對(duì)象的三種方式 1.3 反射常用的方法介紹 1.4 反射的定義 1.5 反射的組成 1.6 反射的作用有哪些 2.反射的...

    ingood 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<