當前位置:開發者網絡 >> 技術教程 >> JSP教程 >> Java技巧及代碼 >> 內容
精彩推薦
分類最新教程
分類熱點教程
    
Java的Package與Import機制之我的理解(初學者的心得)
作者:未知
日期:2005-04-30
人氣:
投稿:(轉貼)
來源:未知
字體:
收藏:加入瀏覽器收藏
以下正文:

   以下內容的測試條件是你的機器上,設置了path命令PATH= D:\JDK1.4\BIN;D:\JDK1.4\LIB;,可以正常執行java和javac命令,不用設置classpath路徑的情況下。




 


    從一個簡單的例子談談package與import機制



基本原則:為什麼需要將Java文件和類文件切實安置到其所歸屬之Package所對應的相對路徑下。



為什麼要這樣做呢?如果你在程序中,用到打包命令package,並且直接編譯和執行該程序。例如:以下面程序為例:

package a.b.c;

public class hello

{

  public static void main(String args[])

  {   

   System.out.println("Hello the world!");

  }

}

此程序可以編譯通過,但是執行時,卻提示以下錯誤!

D:\my\xdj>javac hello.java


 


D:\my\xdj>java hello

Exception in thread "main" java.lang.NoClassDefFoundError: hello (wrong name: a/

b/c/hello)

        at java.lang.ClassLoader.defineClass0(Native Method)

        at java.lang.ClassLoader.defineClass(ClassLoader.java:537)

        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12

3)

        at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)

        at java.net.URLClassLoader.access$100(URLClassLoader.java:55)

        at java.net.URLClassLoader$1.run(URLClassLoader.java:194)

        at java.security.AccessController.doPrivileged(Native Method)

        at java.net.URLClassLoader.findClass(URLClassLoader.java:187)

        at java.lang.ClassLoader.loadClass(ClassLoader.java:289)

        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)

        at java.lang.ClassLoader.loadClass(ClassLoader.java:235)

        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)


 


D:\my\xdj>


 


在xdj目錄下建立一個\a\b\c子目錄把hello.java放在它下面,用以下命令進行編譯和執行時,可正常通過!


 


D:\my\xdj>javac d:\my\xdj\a\b\c\hello.java


 


D:\my\xdj>java a.b.c.hello

Hello the world!


 


D:\my\xdj>


 


再看下面另外一種情況,先讓我們在xdj目錄下建立兩個文件a.java和b.java文件,其內容如下。

a.java文件內容:

import a.b.c.*;

public class a

{

   public static void main(String[] args)

     {

       b b1=new b();

       b1.print();

       }


 


}


 



 



 


a.java文件內容:

package a.b.c;

public class b

{

   public  void print()

     {

      System.out.println("我是被調用子類的程序輸出呀!");

       }

}


 


直接編譯a.java文件時,會提示以下錯誤!


 


D:\my\xdj>javac a.java

a.java:1: package a.b.c does not exist

import a.b.c.*;

^

a.java:6: cannot access b

bad class file: .\b.java

file does not contain class b

Please remove or make sure it appears in the correct subdirectory of the classpa

th.

       b b1=new b();

       ^

2 errors


 


D:\my\xdj>

接下來,我們把b.java移到xdj\a\b\c\下,並把\xdj目錄下的b.java刪除掉呀!重新執行編譯指令,這次肯定可以編譯成功!你可以發現b.java也同時被編譯過了,這就是所謂的make編譯方式。


 


D:\my\xdj>javac a.java


 


D:\my\xdj>


 


提示1:如果你在\xdj目錄下仍保留一個b.java文件的話,執行對主程序的編譯命令時仍會報錯!你自己可以試試呀!

提示2:如果你刪除\xdj\a\b\c\b.java文件的話,保留b.class文件,執行對主程序的編譯命令時是可以通過,此地可以不需要子程序的源代碼。


 


提出一個問題:如果把目錄\a\b\c全部剪切到其它目錄,如D盤根目錄下,在\xdj目錄如果執行編譯和執行命令呢?



很明顯,會報以下錯誤!當然了,前提條件是你沒有設置classpath路徑,其實只要沒把類搜索路徑設置到我這個位置就會出錯的!你試試吧!


 


D:\my\xdj>javac a.java

a.java:1: package a.b.c does not exist

import a.b.c.*;

^

a.java:6: cannot resolve symbol

symbol  : class b

location: class a

       b b1=new b();

       ^

a.java:6: cannot resolve symbol

symbol  : class b

location: class a

       b b1=new b();

                ^

3 errors


 


D:\my\xdj>java a

Exception in thread "main" java.lang.NoClassDefFoundError: a/b/c/b

        at a.main(a.java:6)


 


D:\my\xdj>

解決的辦法可以用以下命令即可正常編譯和執行:


 


D:\my\xdj>javac -classpath  d:\   a.java


 


D:\my\xdj>java -classpath  d:\;a

我是被調用子類的程序輸出呀!


 


D:\my\xdj>


 


提示3:-classpath參數,缺省是以當前目錄為根基目錄的,即不帶-classpath參數的情況下。

提示4:使用java.exe還是javac.exe,最好明確指定-classpath選項,可設置環境變量CLASSPATH即可,同時設置了-classpath參數和環境變量classpath時,會以-classpath參數為主的。如果在它們所指定的路徑或JAR文件中存有package名稱和類名稱相同的類,會引起混淆的!


 


如果你在D盤的根目錄生成一個打包文件a.zip,其內容目錄a\b\c\下的所有文件的話,你也可以用下面命令進行編譯和執行。

D:\my\xdj>javac -classpath d:\a.zip a.java


 


D:\my\xdj>java -classpath d:\a.zip;. a

我是被調用子類的程序輸出呀!


 


D:\my\xdj>


 


以上討論就暫告一段落吧!如果你還想進一步瞭解package與import機制話,哪你可以繼續往下看下去的。


 


深入分析package與import機制部分



不管你有沒有使用import指令,存在目前目錄下的類都會被編譯器優先採用,只要它不屬於任何package。這是因為編譯器總是先假設您所輸入的類名就是該類的全名(不屬於任何package),然後-classpath所指定的路徑中搜索屬於該類的.java文件或.class文件,在這裡可以知道default package的角色非常特殊。

必須明確告訴編譯器我們用到哪個package下的類,導入時或在包名稱.類名稱中進行引用。導入某個包時,一定要進行-classpath路徑指定某個包的位置。你如果指定了多個路徑話,如果在一個路徑下已經找到了該包話,就優先引用該包的類。

當java編譯器開始編譯某個類的源代碼時,首先它會做一件事情,這就是建立“類路徑引用表”,它是根據參數-classpath或classpath環境變量來建立的。如果沒有指定選項-classpath或環境變量CLASSPATH時,缺省情況下類路徑引用表只有一筆記錄,即當前的目錄(“.”)。環境變量CLASSPATH的內容會被選項-classpath所覆蓋,沒有累加效果。

   當編譯器將類路徑引用表建立好之後,接著編譯器要確定它可以利用類引用表裡的數據作為相對起始路徑,找到所有用到的package。

   編譯器還要完成一張名為“類引用表”與“相對類引用表”的數據結構。

   整個編譯程序中package與import機制相關的部分流程如下:


 


開始,


 


建立類路徑引用表與類引用表;

    如果建立成功:則類名稱解析程序:

如果已存在該類的類文件,繼續其它的編譯工作。

如果該類的文件不存在,尋找該類的源代碼文件:

                         如果找到,則編譯該

                          類的源代碼,繼續

                           其它的編譯工作。

                           此時,也可返回到

開始,make機制,

遞歸式編譯。

                         如果找不到,編譯



結束,發出警告



信息。

    如果建立失敗:編譯結束,發出警告信息(2)。


 



 


JAVA動態鏈接本質研究



不管你在同一個源代碼(.java)中使用了幾個類聲明,它們都會一一編譯成.class文件,即使是內部類、匿名類都是一樣。在java中,對於每一個類所構成的類文件,都可將它視為動態鏈接庫。

在類文件中,所有對於特寫類的操作都被轉換成類的全名。Import除了用來指引編譯器解析出正確的類名稱之外,沒有其它功能。

在運行時期,仍然用到一個與編譯器相同的程序,就是類路徑引用表的建立,而利用動態鏈接載入類文件的機制流程如下:

開始,

建立類路徑引用表,

根據類文件內部的信息,與類路徑引用表的數據合成類文件的絕對路徑。

    如果找到類文件,檢查該類的類文件內部信息,是否符合相對路徑信息:

                                                  如果符合,載入該類。

                                                  如果不符合,執行錯誤,發出

                                                     Exception信息。

    如果找不到類文件,則執行錯誤,發出Exception信息。


 


最後,需要說明的是,在java中提供許多的類包,java語言中將完成與計算機底層相關的輸入輸出、常用的數據類型轉換等功能的函數封裝在包中。如果你的程序提示找不到這樣基礎包的話,你就可以用參數-classpath或環境變量classpath進行指定位置來解決此類問題!

後面寫的有點亂呀!不知道你能否理解呀!不過相信你看完我對package與import的討論後,應該會有所收穫的。如果你還有任何關於package與import的疑問的話,可以和我一起討論和交流呀!我的郵箱是:xiaodajin@sina.com。


相關文章: