這篇文章起源于程序員之家論壇(http://www.sunxin.org)上的一個網(wǎng)友的提問,我對他的問題做了回答。具體網(wǎng)址:http://www.sunxin.org/bbs/dispbbs.asp?boardID=6&ID=12289&page=1
我感覺這個問題的答案對Java的初學者來說,會有一定的幫助,所以將問題和答案整理成文。
問題
首先新建一個目錄存放Java源文件,或者直接在某個盤符下放置程序,例如:D:",然后按照下面的步驟進行實驗(本實驗在D:"目錄下操作)。
Step1:編寫程序World.java,代碼如下:
package a;
public class World
{
public World()
{
System.out.println(", World!");
}
}
import a.World;
public class Hello
{
public static void main(String[] args)
{
System.out.print("Hello");
World world = new World();
}
Step3:將兩個程序保存到你所建的目錄下,在這里,我們將它們保存到D:"下。
Step4:編譯這兩個Java源文件
先編譯World.java,執(zhí)行javac -d . World.java,在D盤生成目錄a,及其中的World.class。接下來編譯Hello.java,執(zhí)行javac Hello.java,在D盤上生成Hello.class。
Step5:運行Hello類
執(zhí)行java Hello,輸出Hello, World!目前一切正常。
Step6:修改Hello.java
將第1行的語句“import a.World;”改為“import a.*;”,重新編譯Hello.java,出現(xiàn)下面的錯誤提示:
錯誤的類文件: ."World.java
文件不包含類 World
請刪除該文件或確保該文件位于正確的類路徑子目錄中。
World world = new World();
Step7:根據(jù)錯誤提示進行下列操作
按照錯誤提示,刪除 World.java 或者將 World.java 放到其他地方,則程序成功編譯運行。
問題:
請問為何會出現(xiàn)Step6中的錯誤呢?使用 “import a.*;”導入a下所有類和接口,和使用“import a.World;”導入a包中具體的類,為何會產(chǎn)生上述的差異呢?
回答
當你導入一個包中所有的類時,javac在編譯時并不確定你要使用的World類是a包中的類,還是其他包中的類,它會根據(jù)你機器上的CLASSPATH環(huán)境變量的值去查找類,通常我們在CLASSPATH中會設(shè)置一個點(.),表示當前目錄,如果沒有CLASSPATH環(huán)境變量,那么在JDK1.4之后,默認也是查找當前目錄。javac在按照文件名(不包括后綴)來查找類,于是找到World.java,而這個文件根本不是字節(jié)碼文件,當然就報錯了。當你導入一個具體的類時,javac在分析源文件時就知道了你程序中用的類是a.World,那么它就在CLASSPATH環(huán)境變量下查找a目錄下的World類,正好有,于是正確執(zhí)行。
為了幫助讀者對這個問題加深理解,我給大家設(shè)計了下面的操作步驟(本文是在D盤上操作):
(1)將a目錄剪切到C:"下;
(2)再次執(zhí)行javac Hello.java,你會看到同樣的錯誤。也就是證實了在出錯之前,javac還沒有去查找a包中的類(對于包是否存在的驗證已經(jīng)進行)。
(3)執(zhí)行set classpath=c:"。由于你明確地設(shè)置了CLASSPATH環(huán)境變量的值,并且沒有包含點(.),因此javac不會再查找當前的目錄。
(4)再次執(zhí)行javac Hello.java,你會發(fā)現(xiàn)成功執(zhí)行。
這里面還有一個有趣的現(xiàn)象,如果我們將a目錄下的World.class刪除,替換為World.java,那么在編譯Hello.java時,World也會被自動編譯。