<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    sharajava

    類的動態(tài)加載

    : 調(diào)用 Class.forName() ClassLoader.loadClass() 的區(qū)別在什么地方 ?

    : 這兩方法都是通過一個給定的類名去定位和加載這個類名對應(yīng)的 java.long.Class 類對象 . 盡管如此 , 它們的在行為方式上還是有區(qū)別的 .

    ????????? 用哪個 java.lang.ClassLoader 進(jìn)行加載

    ????????? 返回的 Class 對象是否被初始化

    Class.forName(String) 方法(只有一個參數(shù)), 使用調(diào)用者的類加載器來加載, 也就是用加載了調(diào)用forName方法的代碼的那個類加載器. 相應(yīng)的, ClassLoader.loadClass()方法是一個實(shí)例方法(非靜態(tài)方法), 調(diào)用時需要自己指定類加載器, 那么這個類加載器就可能是也可能不是加載調(diào)用代碼的類加載器. 如果用特定的類加載器來加載類在你的設(shè)計中占有比較重要的地位, 你就應(yīng)該調(diào)用ClassLoader.loadClass(String)方法或Class.forName(String, boolean, ClassLoader)方法.

    ??? 另外, Class.forName()方法對加載的類對象進(jìn)行初始化. 可見的效果就是類中靜態(tài)初始化段及字節(jié)碼中對所有靜態(tài)成員的初始工作的執(zhí)行(這個過程在類的所有父類中遞歸地調(diào)用). 這點(diǎn)就與ClassLoader.loadClass()不同. ClassLoader.loadClass()加載的類對象是在第一次被調(diào)用時才進(jìn)行初始化的.

    ??? 你可以利用上述的差異. 比如,要加載一個靜態(tài)初始化開銷很大的類, 你就可以選擇提前加載該類(以確保它在classpath), 但不進(jìn)行初始化, 直到第一次使用該類的域或方法時才進(jìn)行初始化.

    ??? 最常用的是Class.forName(String, boolean, ClassLoader). 設(shè)置第二個參數(shù)為false即推遲初始化, 第三個參數(shù)指定要用來進(jìn)行加載的類加載器. 我建議為了最大的靈活性使用這個方法.

    類初始化錯誤是難處理的

    ??? 成功地加載了類, 并不意味著就不會有其它問題. 靜態(tài)初始化代碼可以拋出異常, 異常被包裝到java.long.ExceptionInInitializerError的實(shí)例中. 異常拋出后, 這個類將不可用. 這樣, 如果你需要在代碼中處理這些錯誤, 你就應(yīng)該調(diào)用進(jìn)行初始化的Class.forName()方法.

    ??? 但進(jìn)一步說, 如果你要處理ExceptionInInitializerError并試圖從錯誤中恢復(fù), 很可能不如你想象的那樣正常工作. 請看下面的示例代碼:


    public ? class ?Main
    {
    ????
    public ? static ? void ?main?(String?[]?args)? throws ?Exception
    ????{
    ????????
    for ?( int ?repeat?=?0;?repeat?<?3;?++?repeat)
    ????????{
    ????????????
    try
    ????????????{
    ????????????????
    //?"Real"?name?for?X?is?outer?class?name+$+nested?class?name:
    ????????????????Class.forName?("Main$X");
    ????????????}
    ????????????
    catch ?(Throwable?t)
    ????????????{
    ????????????????System.out.println?("load?attempt?#"?+?repeat?+?":");
    ????????????????t.printStackTrace?(System.out);
    ????????????}
    ????????}
    ????}

    ????
    private ? static ? class ?X
    ????{
    ????????
    static
    ????????{
    ????????????
    if ?(++?s_count?==?1)
    ????????????????
    throw ? new ?RuntimeException?("failing?static?initializer");
    ????????}
    ????????
    ????}?
    //?End?of?nested?class

    ????
    private ? static ? int ?s_count;

    }?
    //?End?of?class

    ??? 上面的代碼3次嘗試加載一個內(nèi)部類X, 即便是X的靜態(tài)初始化只在每一次加載時失敗, 3次加載都拋出了異常.

    >java Main
    load attempt #0:
    java.lang.ExceptionInInitializerError
    ????????at java.lang.Class.forName0(Native Method)
    ????????at java.lang.Class.forName(Class.java:140)
    ????????at Main.main(Main.java:17)
    Caused by: java.lang.RuntimeException: failing static initializer...
    ????????at Main$X.<clinit>(Main.java:40)
    ????????... 3 more
    load attempt #1:
    java.lang.NoClassDefFoundError
    ????????at java.lang.Class.forName0(Native Method)
    ????????at java.lang.Class.forName(Class.java:140)
    ????????at Main.main(Main.java:17)
    load attempt #2:
    java.lang.NoClassDefFoundError
    ????????at java.lang.Class.forName0(Native Method)
    ????????at java.lang.Class.forName(Class.java:140)
    ????????at Main.main(Main.java:17)

    ??? 有點(diǎn)令人吃驚的時, 在第2, 3次進(jìn)行類加載時, 拋出的異常竟然是java.lang.NoClassDefFoundError. 這里發(fā)生的事情是, 第一次加載后(在進(jìn)行初始化之前), JVM發(fā)現(xiàn)X已經(jīng)被加載, 而這個X的類實(shí)例在加載它的類加載器被垃圾回收之前是不會被卸載的. 所以這之后的對Class.forName()的調(diào)用時, JVM不會再嘗試進(jìn)行初始化的工作, 但是, 更令人不解的是, 拋出一個NoClassDefFoundError.

    ??? 卸載這樣的類的方法是丟棄原來加載該類的類加載器實(shí)例并重新創(chuàng)建一個. 當(dāng)然, 這只能是在你使用了Class.forName(String, boolean, ClassLoader)這個3參數(shù)的方法的時候才能辦到.

    隱藏的 Class.forName() 方法

    ??? 你一定用過JavaX.class的語法去獲取一個在編譯器就知道名字的類對象實(shí)例. 在字節(jié)碼的層次上, 這一點(diǎn)是如何實(shí)現(xiàn)的就不被人熟知了. 不同的編譯器有不同的實(shí)例細(xì)節(jié), 但共同點(diǎn)是, 所有編譯器所相應(yīng)產(chǎn)生的代碼都是調(diào)用的Class.forName(String)這一個參數(shù)的方法. 比如J2SE 1.4.1javac就把Class cls = X.class; 翻譯成如下等價的形式:

    ?
    ????????
    //?This?is?how?"Class?cls?=?X.class"?is?transformed:
    ???????? if ?( class $Main$X?==? null )
    ????????{
    ????????????
    class $Main$X?=? class $?("Main$X");
    ????????}
    ????????Class?cls?=?
    class $Main$X;

    ????

    ????
    static ?Class? class $?(String?s)
    ????{
    ????????
    try
    ????????{
    ????????????
    return ?Class.forName?(s);
    ????????}
    ????????
    catch ?(ClassNotFoundException?e)
    ????????{
    ????????????
    throw ? new ?NoClassDefFoundError?(e.getMessage());
    ????????}
    ????}

    ????
    static ?Class? class $Main$X;? //?A?synthetic?field?created?by?the?compiler

    Sun javac 開個玩笑

    從上面的例子你可以看到, 編譯器調(diào)用Class.forName()方法加載類對象, 并將其緩存到一個包內(nèi)可見的靜態(tài)變量中. 這種令人費(fèi)解的實(shí)現(xiàn)方式的可能是因?yàn)樵谠缙诎姹镜?span lang="EN-US">Java, 這種X.class的語法還未被支持, so the feature was added on top of the Java 1.0 byte-code instruction set.(???)

    利用這一點(diǎn), 你可以在編譯器的開銷上做一些有趣的事情. J2SE 1.3.1編譯下面的代碼片段:

    public ? class ?Main
    {
    ????
    public ? static ? void ?main?(String?[]?args)? throws ?Exception
    ????{
    ????????System.out.println?("String?class:?"?+?String.
    class );
    ????????
    class $java$lang$String?=? int . class ;
    ????????System.out.println?("String?class:?"?+?String.
    class );
    ????}
    ????
    ????
    static ?Class? class $java$lang$String;

    }?
    //?End?of?class

    運(yùn)行它, 你會得到下面這個很荒謬的輸出結(jié)果:

    >java Main

    String class: class java.lang.String

    String class: int

    J2SE 1.4.1, 上面的代碼將不能被編譯通過, 但你仍然可以用反射的方式戲弄它:

    public ? static ? void ?main?(String?[]?args)? throws ?Exception
    ????{
    ????????System.out.println?("String?class:?"?+?String.
    class );
    ????????Main.
    class .getDeclaredField?("class$java$lang$String").set?( null ,? int . class );
    ????????System.out.println?("String?class:?"?+?String.
    class );
    ????}

    ?

    ??? 綜上所述, 下次你再調(diào)用Class.forName()方法時, 你應(yīng)該知道它的局限性可選的替代方案了.

    ?

    ?

    posted on 2006-07-27 09:06 sharajava 閱讀(2149) 評論(0)  編輯  收藏 所屬分類: 深入Java底層


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产成人精品日本亚洲直接| 成人性做爰aaa片免费看| 免费v片在线观看无遮挡| 中出五十路免费视频| avtt天堂网手机版亚洲| 一本久到久久亚洲综合| 久久久精品免费视频| 77777午夜亚洲| JLZZJLZZ亚洲乱熟无码| 中文字幕免费观看| 偷自拍亚洲视频在线观看99| 亚洲成AV人片天堂网无码| 毛片在线看免费版| 精品免费久久久久国产一区| 亚洲小视频在线播放| 四虎影视在线永久免费看黄| 国产午夜精品久久久久免费视| 国产亚洲精品影视在线| 久久精品夜色噜噜亚洲A∨| 1000部拍拍拍18免费网站| 日本中文字幕免费看| 亚洲成人一级电影| 亚洲综合最新无码专区| 久久久久久国产精品免费免费| 久久久精品视频免费观看 | 免费一级毛suv好看的国产网站| 亚洲视频2020| 国产成人综合亚洲亚洲国产第一页| 在线看片免费不卡人成视频| a毛片免费全部在线播放**| 亚洲精品色播一区二区| 亚洲国产人成网站在线电影动漫| 免费国产成人午夜私人影视| 国产免费不卡视频| 国产一级片免费看| 国产成人无码精品久久久久免费| 亚洲中文字幕久久久一区| 久久夜色精品国产噜噜噜亚洲AV| 久久久久亚洲AV综合波多野结衣 | 亚洲五月综合缴情在线观看| 成年人在线免费看视频|