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

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

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

    sharajava

    2006年7月27日 #

    類的動態加載

    : 調用 Class.forName() ClassLoader.loadClass() 的區別在什么地方 ?

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

    ????????? 用哪個 java.lang.ClassLoader 進行加載

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

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

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

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

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

    類初始化錯誤是難處理的

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

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


    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次嘗試加載一個內部類X, 即便是X的靜態初始化只在每一次加載時失敗, 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)

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

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

    隱藏的 Class.forName() 方法

    ??? 你一定用過JavaX.class的語法去獲取一個在編譯器就知道名字的類對象實例. 在字節碼的層次上, 這一點是如何實現的就不被人熟知了. 不同的編譯器有不同的實例細節, 但共同點是, 所有編譯器所相應產生的代碼都是調用的Class.forName(String)這一個參數的方法. 比如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 開個玩笑

    從上面的例子你可以看到, 編譯器調用Class.forName()方法加載類對象, 并將其緩存到一個包內可見的靜態變量中. 這種令人費解的實現方式的可能是因為在早期版本的Java, 這種X.class的語法還未被支持, so the feature was added on top of the Java 1.0 byte-code instruction set.(???)

    利用這一點, 你可以在編譯器的開銷上做一些有趣的事情. 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

    運行它, 你會得到下面這個很荒謬的輸出結果:

    >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 );
    ????}

    ?

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

    ?

    ?

    posted @ 2006-07-27 09:06 sharajava 閱讀(2149) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 亚洲日本VA中文字幕久久道具| 亚洲乱码精品久久久久..| 亚洲视频在线观看不卡| APP在线免费观看视频| 亚洲色大成网站WWW久久九九| 无码人妻一区二区三区免费视频 | 亚洲一本综合久久| 午夜精品射精入后重之免费观看| 亚洲啪啪综合AV一区| 中文字幕无码毛片免费看| 国产亚洲精品a在线观看app| 精品亚洲永久免费精品| 亚洲性天天干天天摸| 日韩欧毛片免费视频| 亚洲成av人无码亚洲成av人| 国产91久久久久久久免费| 免费激情网站国产高清第一页 | 亚洲国产精品嫩草影院在线观看| 在线观看片免费人成视频无码| 亚洲A∨无码无在线观看| 最近免费字幕中文大全视频| 亚洲一区免费视频| 国产精品冒白浆免费视频| xxxx日本在线播放免费不卡| 亚洲国产精品一区二区第一页| 4399影视免费观看高清直播| 亚洲a级成人片在线观看| 国产亚洲精品免费| 四虎影视无码永久免费| 亚洲婷婷综合色高清在线| 国产精品成人四虎免费视频| 一区二区三区在线观看免费| 美女视频黄的免费视频网页| 午夜国产大片免费观看| 一级毛片无遮挡免费全部| 亚洲五月激情综合图片区| 日本人护士免费xxxx视频| 日本免费A级毛一片| 亚洲伊人久久大香线蕉| 亚洲高清偷拍一区二区三区| 免费国产污网站在线观看15|