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

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

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

    菠蘿三國

    大江東去,浪淘盡...
    隨筆 - 34, 文章 - 47, 評(píng)論 - 22, 引用 - 0
    數(shù)據(jù)加載中……

    了解Java ClassLoader

     

    【原文地址:https://www6.software.ibm.com/developerworks/cn/education/java/j-classloader/tutorial/】
    1.介紹
    2.ClassLoader的結(jié)構(gòu)
    3.Compiling ClassLoader
    4.java2 中ClassLoader的變動(dòng)
    5.源代碼
    ---------------------------------------------------------------------------

    第一章 介紹

    什么是 ClassLoader

    在流行的商業(yè)化編程語言中,Java 語言由于在 Java 虛擬機(jī) (JVM) 上運(yùn)行而顯得與眾不同。這意味著已編譯的程序是一種特殊的、獨(dú)立于平臺(tái)的格式,并非依賴于它們所運(yùn)行的機(jī)器。在很大程度上,這種格式不同于傳統(tǒng)的可執(zhí)行程序格式。

    與 C 或 C++ 編寫的程序不同,Java 程序并不是一個(gè)可執(zhí)行文件,而是由許多獨(dú)立的類文件組成,每一個(gè)文件對(duì)應(yīng)于一個(gè) Java 類。

    此外,這些類文件并非立即全部都裝入內(nèi)存,而是根據(jù)程序需要裝入內(nèi)存。ClassLoader 是 JVM 中將類裝入內(nèi)存的那部分。

    而且,Java ClassLoader 就是用 Java 語言編寫的。這意味著創(chuàng)建您自己的 ClassLoader 非常容易,不必了解 JVM 的微小細(xì)節(jié)。

    為什么編寫 ClassLoader?

    如果 JVM 已經(jīng)有一個(gè) ClassLoader,那么為什么還要編寫另一個(gè)呢?問得好。缺省的 ClassLoader 只知道如何從本地文件系統(tǒng)裝入類文件。不過這只適合于常規(guī)情況,即已全部編譯完 Java 程序,并且計(jì)算機(jī)處于等待狀態(tài)。

    但 Java 語言最具新意的事就是 JVM 可以非常容易地從那些非本地硬盤或從網(wǎng)絡(luò)上獲取類。例如,瀏覽者可以使用定制的 ClassLoader 從 Web 站點(diǎn)裝入可執(zhí)行內(nèi)容。

    有許多其它方式可以獲取類文件。除了簡單地從本地或網(wǎng)絡(luò)裝入文件以外,可以使用定制的 ClassLoader 完成以下任務(wù):

    • 在執(zhí)行非置信代碼之前,自動(dòng)驗(yàn)證數(shù)字簽名
    • 使用用戶提供的密碼透明地解密代碼
    • 動(dòng)態(tài)地創(chuàng)建符合用戶特定需要的定制化構(gòu)建類
    任何您認(rèn)為可以生成 Java 字節(jié)碼的內(nèi)容都可以集成到應(yīng)用程序中。

    定制 ClassLoader 示例

    如果使用過 JDK 或任何基于 Java 瀏覽器中的 Applet 查看器,那么您差不多肯定使用過定制的 ClassLoader。

    Sun 最初發(fā)布 Java 語言時(shí),其中最令人興奮的一件事是觀看這項(xiàng)新技術(shù)是如何執(zhí)行在運(yùn)行時(shí)從遠(yuǎn)程的 Web 服務(wù)器裝入的代碼。(此外,還有更令人興奮的事 -- Java 技術(shù)提供了一種便于編寫代碼的強(qiáng)大語言。)更一些令人激動(dòng)的是它可以執(zhí)行從遠(yuǎn)程 Web 服務(wù)器通過 HTTP 連接發(fā)送過來的字節(jié)碼。

    此項(xiàng)功能歸功于 Java 語言可以安裝定制 ClassLoader。Applet 查看器包含一個(gè) ClassLoader,它不在本地文件系統(tǒng)中尋找類,而是訪問遠(yuǎn)程服務(wù)器上的 Web 站點(diǎn),經(jīng)過 HTTP 裝入原始的字節(jié)碼文件,并把它們轉(zhuǎn)換成 JVM 內(nèi)的類。

    瀏覽器和 Applet 查看器中的 ClassLoaders 還可以做其它事情:它們支持安全性以及使不同的 Applet 在不同的頁面上運(yùn)行而互不干擾。

    Luke Gorrie 編寫的 Echidna 是一個(gè)開放源碼包,它可以使您在單個(gè)虛擬機(jī)上運(yùn)行多個(gè) Java 應(yīng)用程序。(請(qǐng)參閱進(jìn)一步了解和參考資料。)它使用定制的 ClassLoader,通過向每個(gè)應(yīng)用程序提供該類文件的自身副本,以防止應(yīng)用程序互相干擾。


    我們的 ClassLoader 示例

    了解了 ClassLoader 如何工作以及如何編寫 ClassLoader 之后,我們將創(chuàng)建稱作 CompilingClassLoader (CCL) 的 Classloader。CCL 為我們編譯 Java 代碼,而無需要我們干涉這個(gè)過程。它基本上就類似于直接構(gòu)建到運(yùn)行時(shí)系統(tǒng)中的 "make" 程序。

    注:進(jìn)一步了解之前,應(yīng)注意在 JDK 版本 1.2 中已改進(jìn)了 ClassLoader 系統(tǒng)的某些方面(即 Java 2 平臺(tái))。本教程是按 JDK 版本 1.0 和 1.1 寫的,但也可以在以后的版本中運(yùn)行。

    Java 2 中 ClassLoader 的變動(dòng)描述了 Java 版本 1.2 中的變動(dòng),并提供了一些詳細(xì)信息,以便修改 ClassLoader 來利用這些變動(dòng)。

     


     

    ------------------------------------------------------------------------------------------------------

    第二章.ClassLoader的結(jié)構(gòu)



    ClassLoader 的基本目標(biāo)是對(duì)類的請(qǐng)求提供服務(wù)。當(dāng) JVM 需要使用類時(shí),它根據(jù)名稱向 ClassLoader 請(qǐng)求這個(gè)類,然后 ClassLoader 試圖返回一個(gè)表示這個(gè)類的 Class 對(duì)象。

    通過覆蓋對(duì)應(yīng)于這個(gè)過程不同階段的方法,可以創(chuàng)建定制的 ClassLoader。

    在本章的其余部分,您會(huì)學(xué)習(xí) Java ClassLoader 的關(guān)鍵方法。您將了解每一個(gè)方法的作用以及它是如何適合裝入類文件這個(gè)過程的。您也會(huì)知道,創(chuàng)建自己的 ClassLoader 時(shí),需要編寫什么代碼。

    在下一章中,您將會(huì)利用這些知識(shí)來使用我們的 ClassLoader 示例 -- CompilingClassLoader。


    方法 loadClass


    ClassLoader.loadClass() 是 ClassLoader 的入口點(diǎn)。其特征如下:

     

    Class loadClass( String name, boolean resolve );

    name 參數(shù)指定了 JVM 需要的類的名稱,該名稱以包表示法表示,如 Foojava.lang.Object。

    resolve 參數(shù)告訴方法是否需要解析類。在準(zhǔn)備執(zhí)行類之前,應(yīng)考慮類解析。并不總是需要解析。如果 JVM 只需要知道該類是否存在或找出該類的超類,那么就不需要解析。

    在 Java 版本 1.1 和以前的版本中,loadClass 方法是創(chuàng)建定制的 ClassLoader 時(shí)唯一需要覆蓋的方法。(Java 2 中 ClassLoader 的變動(dòng)提供了關(guān)于 Java 1.2 中 findClass() 方法的信息。)


    方法 defineClass

    defineClass 方法是 ClassLoader 的主要訣竅。該方法接受由原始字節(jié)組成的數(shù)組并把它轉(zhuǎn)換成 Class 對(duì)象。原始數(shù)組包含如從文件系統(tǒng)或網(wǎng)絡(luò)裝入的數(shù)據(jù)。

    defineClass 管理 JVM 的許多復(fù)雜、神秘和倚賴于實(shí)現(xiàn)的方面 -- 它把字節(jié)碼分析成運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)、校驗(yàn)有效性等等。不必?fù)?dān)心,您無需親自編寫它。事實(shí)上,即使您想要這么做也不能覆蓋它,因?yàn)樗驯粯?biāo)記成最終的。


    方法 findSystemClass

    findSystemClass 方法從本地文件系統(tǒng)裝入文件。它在本地文件系統(tǒng)中尋找類文件,如果存在,就使用 defineClass 將原始字節(jié)轉(zhuǎn)換成 Class 對(duì)象,以將該文件轉(zhuǎn)換成類。當(dāng)運(yùn)行 Java 應(yīng)用程序時(shí),這是 JVM 正常裝入類的缺省機(jī)制。(Java 2 中 ClassLoader 的變動(dòng)提供了關(guān)于 Java 版本 1.2 這個(gè)過程變動(dòng)的詳細(xì)信息。)

    對(duì)于定制的 ClassLoader,只有在嘗試其它方法裝入類之后,再使用 findSystemClass。原因很簡單:ClassLoader 是負(fù)責(zé)執(zhí)行裝入類的特殊步驟,不是負(fù)責(zé)所有類。例如,即使 ClassLoader 從遠(yuǎn)程的 Web 站點(diǎn)裝入了某些類,仍然需要在本地機(jī)器上裝入大量的基本 Java 庫。而這些類不是我們所關(guān)心的,所以要 JVM 以缺省方式裝入它們:從本地文件系統(tǒng)。這就是 findSystemClass 的用途。

    其工作流程如下:

     

    • 請(qǐng)求定制的 ClassLoader 裝入類。
    • 檢查遠(yuǎn)程 Web 站點(diǎn),查看是否有所需要的類。
    • 如果有,那么好;抓取這個(gè)類,完成任務(wù)。
    • 如果沒有,假定這個(gè)類是在基本 Java 庫中,那么調(diào)用 findSystemClass,使它從文件系統(tǒng)裝入該類。

    在大多數(shù)定制 ClassLoaders 中,首先調(diào)用 findSystemClass 以節(jié)省在本地就可以裝入的許多 Java 庫類而要在遠(yuǎn)程 Web 站點(diǎn)上查找所花的時(shí)間。然而,正如,在下一章節(jié)所看到的,直到確信能自動(dòng)編譯我們的應(yīng)用程序代碼時(shí),才讓 JVM 從本地文件系統(tǒng)裝入類。


    方法 resolveClass

    正如前面所提到的,可以不完全地(不帶解析)裝入類,也可以完全地(帶解析)裝入類。當(dāng)編寫我們自己的 loadClass 時(shí),可以調(diào)用 resolveClass,這取決于 loadClassresolve 參數(shù)的值。

    方法 findLoadedClass

    findLoadedClass 充當(dāng)一個(gè)緩存:當(dāng)請(qǐng)求 loadClass 裝入類時(shí),它調(diào)用該方法來查看 ClassLoader 是否已裝入這個(gè)類,這樣可以避免重新裝入已存在類所造成的麻煩。應(yīng)首先調(diào)用該方法。

    組裝

     

     

     

    讓我們看一下如何組裝所有方法。

    我們的 loadClass 實(shí)現(xiàn)示例執(zhí)行以下步驟。(這里,我們沒有指定生成類文件是采用了哪種技術(shù) -- 它可以是從 Net 上裝入、或者從歸檔文件中提取、或者實(shí)時(shí)編譯。無論是哪一種,那是種特殊的神奇方式,使我們獲得了原始類文件字節(jié)。)

     

    • 調(diào)用 findLoadedClass 來查看是否存在已裝入的類。

    • 如果沒有,那么采用那種特殊的神奇方式來獲取原始字節(jié)。

    • 如果已有原始字節(jié),調(diào)用 defineClass 將它們轉(zhuǎn)換成 Class 對(duì)象。

    • 如果沒有原始字節(jié),然后調(diào)用 findSystemClass 查看是否從本地文件系統(tǒng)獲取類。

    • 如果 resolve 參數(shù)是 true,那么調(diào)用 resolveClass 解析 Class 對(duì)象。

    • 如果還沒有類,返回 ClassNotFoundException。

    • 否則,將類返回給調(diào)用程序。
    推想

    現(xiàn)在您已經(jīng)了解了 ClassLoader 的工作原理,現(xiàn)在該構(gòu)建一個(gè)了。在下一章中,我們將討論 CCL。

    ---------------------------------------------------------------------------------------------

    第三章:Compiling ClassLoader

    CCL 揭密

    我們的 ClassLoader (CCL) 的任務(wù)是確保代碼被編譯和更新。

    下面描述了它的工作方式:

     

    • 當(dāng)請(qǐng)求一個(gè)類時(shí),先查看它是否在磁盤的當(dāng)前目錄或相應(yīng)的子目錄。

    • 如果該類不存在,但源碼中有,那么調(diào)用 Java 編譯器來生成類文件。

    • 如果該類已存在,檢查它是否比源碼舊。如果是,調(diào)用 Java 編譯器來重新生成類文件。

    • 如果編譯失敗,或者由于其它原因不能從現(xiàn)有的源碼中生成類文件,返回 ClassNotFoundException。

    • 如果仍然沒有該類,也許它在其它庫中,所以調(diào)用 findSystemClass 來尋找該類。

    • 如果還是沒有,則返回 ClassNotFoundException。

    • 否則,返回該類。
    Java 編譯的工作方式

     

    在深入討論之前,應(yīng)該先退一步,討論 Java 編譯。通常,Java 編譯器不只是編譯您要求它編譯的類。它還會(huì)編譯其它類,如果這些類是您要求編譯的類所需要的類。

    CCL 逐個(gè)編譯應(yīng)用程序中的需要編譯的每一個(gè)類。但一般來說,在編譯器編譯完第一個(gè)類后,CCL 會(huì)查找所有需要編譯的類,然后編譯它。為什么?Java 編譯器類似于我們正在使用的規(guī)則:如果類不存在,或者與它的源碼相比,它比較舊,那么它需要編譯。其實(shí),Java 編譯器在 CCL 之前的一個(gè)步驟,它會(huì)做大部分的工作。

    當(dāng) CCL 編譯它們時(shí),會(huì)報(bào)告它正在編譯哪個(gè)應(yīng)用程序上的類。在大多數(shù)的情況下,CCL 會(huì)在程序中的主類上調(diào)用編譯器,它會(huì)做完所有要做的 -- 編譯器的單一調(diào)用已足夠了。

    然而,有一種情形,在第一步時(shí)不會(huì)編譯某些類。如果使用 Class.forName 方法,通過名稱來裝入類,Java 編譯器會(huì)不知道這個(gè)類時(shí)所需要的。在這種情況下,您會(huì)看到 CCL 再次運(yùn)行 Java 編譯器來編譯這個(gè)類。在源代碼中演示了這個(gè)過程。

    使用 CompilationClassLoader

    要使用 CCL,必須以特殊方式調(diào)用程序。不能直接運(yùn)行該程序,如:

     

    % java Foo arg1 arg2

    應(yīng)以下列方式運(yùn)行它:

     

    % java CCLRun Foo arg1 arg2

    CCLRun 是一個(gè)特殊的存根程序,它創(chuàng)建 CompilingClassLoader 并用它來裝入程序的主類,以確保通過 CompilingClassLoader 來裝入整個(gè)程序。CCLRun 使用 Java Reflection API 來調(diào)用特定類的主方法并把參數(shù)傳遞給它。有關(guān)詳細(xì)信息,請(qǐng)參閱源代碼

    運(yùn)行示例

    源碼包括了一組小類,它們演示了工作方式。主程序是 Foo 類,它創(chuàng)建類 Bar 的實(shí)例。類 Bar 創(chuàng)建另一個(gè)類 Baz 的實(shí)例,它在 baz 包內(nèi),這是為了展示 CCL 是如何處理子包里的代碼。Bar 也是通過名稱裝入的,其名稱為 Boo,這用來展示它也能與 CCL 工作。

    每個(gè)類都聲明已被裝入并運(yùn)行。現(xiàn)在用源代碼來試一下。編譯 CCLRun 和 CompilingClassLoader。確保不要編譯其它類(Foo、BarBazBoo),否則將不會(huì)使用 CCL,因?yàn)檫@些類已經(jīng)編譯過了。

     


    % java CCLRun Foo arg1 arg2
    CCL: Compiling Foo.java...
    foo! arg1 arg2
    bar! arg1 arg2
    baz! arg1 arg2
    CCL: Compiling Boo.java...
    Boo!

    請(qǐng)注意,首先調(diào)用編譯器,Foo.java 管理 Barbaz.Baz。直到 Bar 通過名稱來裝入 Boo 時(shí),被調(diào)用它,這時(shí) CCL 會(huì)再次調(diào)用編譯器來編譯它。

     

     

     

     

    --------------------------------------------------------------------------------------

    第四章:java2 中ClassLoader的變動(dòng)


    概述

    在 Java 版本 1.2 和以后的版本中,對(duì) ClassLoader 做了一些改進(jìn)。任何為老系統(tǒng)編寫的代碼可以在新版本中運(yùn)行,但新系統(tǒng)為您提供了一些便利。

    新模型是委托模型,這意味著如果 ClassLoader 不能找到類,它會(huì)請(qǐng)求父代 ClassLoader 來執(zhí)行此項(xiàng)任務(wù)。所有 ClassLoaders 的根是系統(tǒng) ClassLoader,它會(huì)以缺省方式裝入類 -- 即,從本地文件系統(tǒng)。

    loadClass 的缺省實(shí)現(xiàn)

    定制編寫的 loadClass 方法一般嘗試幾種方式來裝入所請(qǐng)求的類,如果您編寫許多類,會(huì)發(fā)現(xiàn)一次次地在相同的、很復(fù)雜的方法上編寫變量。

    在 Java 1.2 中 loadClass 的實(shí)現(xiàn)嵌入了大多數(shù)查找類的一般方法,并使您通過覆蓋 findClass 方法來定制它,在適當(dāng)?shù)臅r(shí)候 findClass 會(huì)調(diào)用 loadClass

    這種方式的好處是您可能不一定要覆蓋 loadClass;只要覆蓋 findClass 就行了,這減少了工作量。

    新方法:findClass

    loadClass 的缺省實(shí)現(xiàn)調(diào)用這個(gè)新方法。findClass 的用途包含您的 ClassLoader 的所有特殊代碼,而無需要復(fù)制其它代碼(例如,當(dāng)專門的方法失敗時(shí),調(diào)用系統(tǒng) ClassLoader)。

    新方法:getSystemClassLoader

    如果覆蓋 findClassloadClass,getSystemClassLoader 使您能以實(shí)際 ClassLoader 對(duì)象來訪問系統(tǒng) ClassLoader(而不是固定的從 findSystemClass 調(diào)用它)。

    新方法:getParent

    為了將類請(qǐng)求委托給父代 ClassLoader,這個(gè)新方法允許 ClassLoader 獲取它的父代 ClassLoader。當(dāng)使用特殊方法,定制的 ClassLoader 不能找到類時(shí),可以使用這種方法。

    父代 ClassLoader 被定義成創(chuàng)建該 ClassLoader 所包含代碼的對(duì)象的 ClassLoader。

    ----------------------------------------------------------------------------------

     

     

     

    第五章.源代碼

     

    CompilingClassLoader.java

    以下是 CompilingClassLoader.java 的源代碼

    // $Id$
    import java.io.*;
    /*
    A CompilingClassLoader compiles your Java source on-the-fly. It checks
    for nonexistent .class files, or .class files that are older than their
    corresponding source code.*/
    public class CompilingClassLoader extends ClassLoader
    {
    // Given a filename, read the entirety of that file from disk
    // and return it as a byte array.
    private byte[] getBytes( String filename ) throws IOException {
    // Find out the length of the file
    File file = new File( filename );
    long len = file.length();
    // Create an array that's just the right size for the file's
    // contents
    byte raw[] = new byte[(int)len];
    // Open the file
    FileInputStream fin = new FileInputStream( file );
    // Read all of it into the array; if we don't get all,
    // then it's an error.
    int r = fin.read( raw );
    if (r != len)
    throw new IOException( "Can't read all, "+r+" != "+len );
    // Don't forget to close the file!
    fin.close();
    // And finally return the file contents as an array
    return raw;
    }
    // Spawn a process to compile the java source code file
    // specified in the 'javaFile' parameter. Return a true if
    // the compilation worked, false otherwise.
    private boolean compile( String javaFile ) throws IOException {
    // Let the user know what's going on
    System.out.println( "CCL: Compiling "+javaFile+"..." );
    // Start up the compiler
    Process p = Runtime.getRuntime().exec( "javac "+javaFile );
    // Wait for it to finish running
    try {
    p.waitFor();
    } catch( InterruptedException ie ) { System.out.println( ie ); }
    // Check the return code, in case of a compilation error
    int ret = p.exitValue();
    // Tell whether the compilation worked
    return ret==0;
    }
    // The heart of the ClassLoader -- automatically compile
    // source as necessary when looking for class files
    public Class loadClass( String name, boolean resolve )
    throws ClassNotFoundException {

    // Our goal is to get a Class object
    Class clas = null;

    // First, see if we've already dealt with this one
    clas = findLoadedClass( name );

    //System.out.println( "findLoadedClass: "+clas );

    // Create a pathname from the class name
    // E.g. java.lang.Object => java/lang/Object
    String fileStub = name.replace( '.', '/' );

    // Build objects pointing to the source code (.java) and object
    // code (.class)
    String javaFilename = fileStub+".java";
    String classFilename = fileStub+".class";

    File javaFile = new File( javaFilename );
    File classFile = new File( classFilename );

    //System.out.println( "j "+javaFile.lastModified()+" c "+
    // classFile.lastModified() );

    // First, see if we want to try compiling. We do if (a) there
    // is source code, and either (b0) there is no object code,
    // or (b1) there is object code, but it's older than the source
    if (javaFile.exists() &&
    (!classFile.exists() ||
    javaFile.lastModified() > classFile.lastModified())) {

    try {
    // Try to compile it. If this doesn't work, then
    // we must declare failure. (It's not good enough to use
    // and already-existing, but out-of-date, classfile)
    if (!compile( javaFilename ) || !classFile.exists()) {
    throw new ClassNotFoundException( "Compile failed: "+javaFilename );
    }
    } catch( IOException ie ) {

    // Another place where we might come to if we fail
    // to compile
    throw new ClassNotFoundException( ie.toString() );
    }
    }

    // Let's try to load up the raw bytes, assuming they were
    // properly compiled, or didn't need to be compiled
    try {

    // read the bytes
    byte raw[] = getBytes( classFilename );

    // try to turn them into a class
    clas = defineClass( name, raw, 0, raw.length );
    } catch( IOException ie ) {
    // This is not a failure! If we reach here, it might
    // mean that we are dealing with a class in a library,
    // such as java.lang.Object
    }

    //System.out.println( "defineClass: "+clas );

    // Maybe the class is in a library -- try loading
    // the normal way
    if (clas==null) {
    clas = findSystemClass( name );
    }

    //System.out.println( "findSystemClass: "+clas );

    // Resolve the class, if any, but only if the "resolve"
    // flag is set to true
    if (resolve && clas != null)
    resolveClass( clas );

    // If we still don't have a class, it's an error
    if (clas == null)
    throw new ClassNotFoundException( name );

    // Otherwise, return the class
    return clas;
    }
     }
    CCRun.java


    以下是 CCRun.java 的源代碼


    // $Id$

    import java.lang.reflect.*;

    /*

    CCLRun executes a Java program by loading it through a
    CompilingClassLoader.

    */

    public class CCLRun
    {
    static public void main( String args[] ) throws Exception {

    // The first argument is the Java program (class) the user
    // wants to run
    String progClass = args[0];

    // And the arguments to that program are just
    // arguments 1..n, so separate those out into
    // their own array
    String progArgs[] = new String[args.length-1];
    System.arraycopy( args, 1, progArgs, 0, progArgs.length );

    // Create a CompilingClassLoader
    CompilingClassLoader ccl = new CompilingClassLoader();

    // Load the main class through our CCL
    Class clas = ccl.loadClass( progClass );

    // Use reflection to call its main() method, and to
    // pass the arguments in.

    // Get a class representing the type of the main method's argument
    Class mainArgType[] = { (new String[0]).getClass() };

    // Find the standard main method in the class
    Method main = clas.getMethod( "main", mainArgType );

    // Create a list containing the arguments -- in this case,
    // an array of strings
    Object argsArray[] = { progArgs };

    // Call the method
    main.invoke( null, argsArray );
    }
    }
    Foo.java


    以下是 Foo.java 的源代碼



    // $Id$

    public class Foo
    {
    static public void main( String args[] ) throws Exception {
    System.out.println( "foo! "+args[0]+" "+args[1] );
    new Bar( args[0], args[1] );
    }
    }
    Bar.java


    以下是 Bar.java 的源代碼


    // $Id$

    import baz.*;

    public class Bar
    {
    public Bar( String a, String b ) {
    System.out.println( "bar! "+a+" "+b );
    new Baz( a, b );

    try {
    Class booClass = Class.forName( "Boo" );
    Object boo = booClass.newInstance();
    } catch( Exception e ) {
    e.printStackTrace();
    }
    }
    }
    baz/Baz.java


    以下是 baz/Baz.java 的源代碼


    // $Id$

    package baz;

    public class Baz
    {
    public Baz( String a, String b ) {
    System.out.println( "baz! "+a+" "+b );
    }
    }

    Boo.java


    以下是 Boo.java 的源代碼


    // $Id$

    public class Boo
    {
    public Boo() {
    System.out.println( "Boo!" );
    }
    }

    posted on 2008-01-25 13:52 菠蘿 閱讀(326) 評(píng)論(0)  編輯  收藏 所屬分類: java


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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产偷窥女洗浴在线观看亚洲| 色吊丝免费观看网站| 亚洲国产精品一区二区第一页免| 中文字幕在线免费观看| 免费看一级一级人妻片| 亚洲熟妇少妇任你躁在线观看| 亚洲成色在线影院| 亚洲色婷婷一区二区三区| 免费人妻av无码专区| 午夜免费福利影院| www.黄色免费网站| 日本免费人成在线网站| 午夜精品一区二区三区免费视频| 国产国产人免费人成成免视频| 成a人片亚洲日本久久| 亚洲AV第一成肉网| 亚洲欧美自偷自拍另类视| 亚洲国产精品成人综合久久久| 亚洲男人天堂2017| 亚洲国产成人久久精品影视| 亚洲成a人片在线观看日本| 久久久久久久亚洲精品| 亚洲人成电影网站国产精品 | 亚洲日韩中文在线精品第一| 国产伦精品一区二区三区免费迷| 日本特黄特色aa大片免费| 男女交性永久免费视频播放| 最近中文字幕无吗免费高清| 美女被免费视频网站a国产| 永久免费av无码网站大全| 国产网站免费观看| 国产99视频精品免费视频7| 国产免费直播在线观看视频| 亚洲M码 欧洲S码SSS222| 亚洲 综合 国产 欧洲 丝袜| 亚洲А∨精品天堂在线| 亚洲国产a级视频| 亚洲人成无码网站| 亚洲色四在线视频观看| 亚洲人成在线中文字幕| 亚洲日韩AV一区二区三区中文|