|
Elliotte Harold (elharo@metalab.unc.edu), 副教授, Polytechnic 大學(xué)
2007 年 1 月 04 日
類路徑是 Java? 平臺(tái)中最復(fù)雜也最令人頭痛的部分之一,但熟練掌握類路徑對(duì)成為一名專業(yè) Java 程序員來(lái)說(shuō)卻又十分關(guān)鍵。在本文中,Elliotte Rusty Harold 為您闡述了類路徑和源路徑的復(fù)雜性,并向您展示了如何在 UNIX 和 Mac OS X 中熟練掌握它們。如果您使用的是 Windows,請(qǐng)參閱本文的 姊妹篇。
類路徑可以連接 Java 運(yùn)行庫(kù)和文件系統(tǒng)。它定義編譯器和解釋器應(yīng)該在何處查找要加載的 .class 文件。它的基本思想是:文件系統(tǒng)的層次結(jié)構(gòu)反映了 Java 包的層次結(jié)構(gòu),而類路徑則定義了文件系統(tǒng)中的哪個(gè)目錄可以作為 Java 包層次結(jié)構(gòu)的根。
遺憾的是,通常文件系統(tǒng)非常復(fù)雜并依賴于平臺(tái),而且和 Java 包也不能很好地匹配。這樣一來(lái),不論是新用戶還是資深 Java 程序員都深感類路徑的棘手。沒(méi)錯(cuò),它的確不是 Java 平臺(tái)好的一面,它讓您到了下班的時(shí)候還在忙于調(diào)試一個(gè)頑固的小問(wèn)題。
當(dāng)然采用 Eclipse 這樣的優(yōu)秀 IDE 可以減少管理類路徑的一些困難,但只能說(shuō)是一些,而且前提還必須是一切都正常(但這不大可能,因?yàn)榭倳?huì)有一些意外出現(xiàn))。因此,每個(gè) Java 程序員都必須要全面了解類路徑,惟有如此,才有希望調(diào)試類路徑中所出現(xiàn)的問(wèn)題。
在本文中,我給出了您所需要了解的有關(guān) UNIX、Linux 和 Mac OS X 中的 Java 類路徑(以及相關(guān)源路徑)的全部?jī)?nèi)容。本文的 姊妹篇 則展示了 Windows 上的類似技術(shù)。文中列出的步驟可以作為指南,并能解決出現(xiàn)的大多數(shù)問(wèn)題。
包結(jié)構(gòu)
要掌握類路徑,首先應(yīng)從其源代碼入手。每個(gè)類都屬于一個(gè)包,而此包必須 遵守標(biāo)準(zhǔn)的命名約定。簡(jiǎn)單地說(shuō),包的名稱要由顛倒的兩級(jí)域名開始,比如 com.example 或 edu.poly,之后是至少一個(gè)或多個(gè)單詞用于描述包的內(nèi)容。比方說(shuō),假設(shè)有一個(gè)域名為 elharo.com,如果要?jiǎng)?chuàng)建一個(gè) Fraction 類,可以將其放入如下包中:
com.elharo.math
com.elharo.numbers
com.elharo.math.algebra.fields
在顛倒的域名之后,需要使用單一單詞的子包名。不要使用縮寫形式,并要保證拼寫正確。如果需要,可以使用拼寫檢查器。大部分與類路徑相關(guān)的問(wèn)題都是由在源代碼中使用某個(gè)單詞而在文件系統(tǒng)中使用的卻是與之稍有不同的拼寫或縮寫而引起的。所以最好的做法就是總是使用拼寫正確且沒(méi)有縮寫的名稱。
整個(gè)包名稱應(yīng)該是小寫的,即使該名稱是在別處常采取大寫形式的一些慣用名稱和縮寫詞。Windows 通常不區(qū)分文件名中的大小寫,但 Java 和一些 UNIX 文件系統(tǒng)卻區(qū)分。如果需要在不同的系統(tǒng)間移動(dòng)文件,大小寫問(wèn)題肯定會(huì)帶來(lái)一些麻煩。包名稱必須要全部由 ASCII 字符組成。一些編譯器也接受用 Hebrew、Cyrillic、Greek 或其他腳本編寫的包名稱,但大多數(shù)文件系統(tǒng)并不接受;您稍后就會(huì)看到,這樣的包名稱必須擔(dān)負(fù)充當(dāng)目錄名這樣的雙重任務(wù)。Java 包和類名是 Unicode,但很多文件系統(tǒng)(包括 FAT)卻不能識(shí)別 Unicode。遺憾的是,F(xiàn)AT 系統(tǒng)非常之多。如果只簡(jiǎn)單地用不同的默認(rèn)編碼將文件復(fù)制到系統(tǒng)將會(huì)使編譯器和解釋器無(wú)法找到正確的類。
 |
用完即棄的代碼
如果您在編寫一個(gè)只使用一次就丟掉的類 —— 比如測(cè)試一個(gè) API 的類 —— 則無(wú)需將它放到包中。但需要多次使用的類必須要放到包中。
|
|
不要試圖在包名稱方面節(jié)約成本。長(zhǎng)遠(yuǎn)來(lái)看,這只會(huì)有百害而無(wú)一利。如果需要域名就買一個(gè)。如果名稱太長(zhǎng)就買個(gè)短些的(我曾經(jīng)買到了 這樣一個(gè)域名,因而我的包前綴就只有 6 個(gè)字符)。不要將類放到默認(rèn)包中(默認(rèn)包是指如果未在類中包含一條包語(yǔ)句時(shí)系統(tǒng)默認(rèn)給出的包)。如果包訪問(wèn)不利于對(duì)象間的通信,就需要向類中添加更多的公共方法。需要多次使用的類必須要放到包中。
目錄結(jié)構(gòu)
下一步要做的是組織源文件來(lái)匹配包結(jié)構(gòu)。在某處創(chuàng)建一個(gè)干凈的空白目錄。本文中,我將其命名為 project。在這個(gè)目錄里,再創(chuàng)建兩個(gè)目錄:bin 和 src。(有些人更喜歡將其分別命名為 build 和 source。)
接下來(lái),在 src 目錄,建一個(gè)與包層次結(jié)構(gòu)相匹配的層次結(jié)構(gòu)。例如,如果給定類名為 com.elharo.math.Fraction,我會(huì)將 com 目錄放到 src 目錄中,然后在 com 目錄中創(chuàng)建一個(gè) elharo 目錄,再在 elharo 目錄內(nèi)放一個(gè) math 目錄,最后在 math 目錄內(nèi)放上 Fraction.java,如圖 1 所示:
圖 1. 目錄結(jié)構(gòu)符合包結(jié)構(gòu)
要點(diǎn):不要在 src 目錄中放置除源代碼之外的任何內(nèi)容。通常這里放入的文件都是 .java 文件。在有些情況下,也可放置 .html 文件(用于 JavaDoc)或其他類型的源代碼。然而,決不能在此結(jié)構(gòu)內(nèi)放置 .class 文件或任何其他編譯并生成的工件。這樣做只會(huì)帶來(lái)麻煩。遺憾的是,如果不夠謹(jǐn)慎,javac 編譯器就會(huì) “明知故犯”。在下一節(jié),將介紹如何修復(fù)這一問(wèn)題。
編譯
編譯 Java 代碼需要一些技巧,原因是必須要跟蹤如下幾方面相關(guān)但又有所不同的內(nèi)容:
- 正在編譯的目標(biāo)文件。
- 編譯器在其中尋找目標(biāo)文件導(dǎo)入 .java 文件的那個(gè)目錄。
- 編譯器在其中尋找目標(biāo)文件導(dǎo)入 .class 文件的那個(gè)目錄。
- 編譯器在其中放置編譯輸出的目錄。
默認(rèn)地,javac 編譯器將上述目錄都認(rèn)為是當(dāng)前目錄,而這并不是您所希望的。因此,需要在編譯時(shí)顯式地指定這些元素。
要編譯的文件
指定的第一個(gè)要編譯的文件是 .java 文件,以從當(dāng)前目錄到該文件的整個(gè)路徑的形式給出。比如,假設(shè)當(dāng)前所在目錄是 圖 1 所示的 project 目錄。該目錄包含 src 目錄。此 src 目錄包含 com 目錄,而 com 目錄又包含 example 目錄,example 目錄下是 Fraction.java 文件。如下命令行對(duì)它進(jìn)行編譯:
$ javac src/com/elharo/math/Fraction.java
|
如果路徑不正確,就會(huì)給出這樣的錯(cuò)誤消息:
error: cannot read: src/com/example/mtah/Fraction.java
|
如果出現(xiàn)這樣的錯(cuò)誤消息,就需要檢查路徑的各個(gè)部分,確保它們拼寫正確。然后再通過(guò)一個(gè)與下面類似的 ls 檢查該文件是否處于它應(yīng)該出現(xiàn)的位置:
$ ls src/com/example/math
ls: src/com/example/math: No such file or directory
|
出現(xiàn)問(wèn)題的原因通常是因?yàn)槁窂狡磳戝e(cuò)誤,但也可能是由于當(dāng)前的目錄不對(duì)。在本例中,需要檢查當(dāng)前的工作目錄是不是 project 目錄。pwd 命令在這里非常有用。例如,以下命令將告訴我,我實(shí)際上處于 project/src 而不是 project 目錄中:
$ pwd
/Users/elharo/documents/articles/classpath/project/src
|
在編譯之前,我需要執(zhí)行 cd ..。
輸出到哪里
假設(shè)沒(méi)有出現(xiàn)任何語(yǔ)法錯(cuò)誤,javac 將編譯后的 .class 文件放到與之對(duì)應(yīng)的.java 文件所在的相同目錄內(nèi)。這并不是您所想要的結(jié)果。將 .class 和 .java 文件混在一起常常會(huì)使清理編譯后的文件十分困難,因?yàn)楹芸赡軙?huì)意外刪除本應(yīng)保留的 .java 文件。這常會(huì)使清理構(gòu)建十分困難,而且還會(huì)導(dǎo)致版本問(wèn)題。發(fā)布一個(gè)二進(jìn)制時(shí),只對(duì)編譯后的 .class 文件進(jìn)行歸檔也會(huì)十分困難。因此,需要告知編譯器將編譯后的輸出放到一個(gè)完全不同的目錄內(nèi)。-d 開關(guān)用來(lái)指定輸出目錄(通常稱為 bin、build 或 class):
$ javac -d bin src/com/elharo/math/Fraction.java
|
現(xiàn)在輸出如圖 2.所示,注意 javac 已建立了完整的目錄層次結(jié)構(gòu) com/elharo/math。不需要再手動(dòng)建立。
圖 2. 并行源和編譯后的層次結(jié)構(gòu)
源路徑
源路徑 就是 Java 在其中尋找源文件的那個(gè)目錄。具體到本例,就是 src 目錄。該目錄必須包含源文件的層次結(jié)構(gòu),這些源文件可以被放到它們自己的目錄中。因此它不是 com 目錄也不是 src/com/elharo/math 目錄。
很多項(xiàng)目都使用不止一個(gè)類和包。它們通過(guò)導(dǎo)入語(yǔ)句和完整的包限定類名連接起來(lái)。例如,假設(shè)您在 com.elharo.gui 包里面創(chuàng)建一個(gè)新的 MainFrame 類 如清單 1 所示:
清單 1. 一個(gè)包中的類可以導(dǎo)入另一個(gè)包中的類
package com.elharo.gui;
import com.elharo.math.*;
public class MainFrame {
public static void main(String[] args) {
Fraction f = new Fraction();
// ...
}
}
|
該類使用的是與 MainFrame 類所在的包不同的包中的 com.elharo.math.Fraction 類。源設(shè)置現(xiàn)在應(yīng)該如圖 3 所示(我將編譯后的輸出從之前的步驟中刪除了。但這沒(méi)有關(guān)系,因?yàn)槲铱偸悄苤匦戮幾g它)。
圖 3. 幾個(gè)包的源結(jié)構(gòu)
現(xiàn)在來(lái)看一下試著像以前一樣編譯 MainFrame.java 會(huì)出現(xiàn)什么情況。
清單 2. 編譯 MainFrame.java
$ javac -d bin src/com/elharo/gui/MainFrame.java
src/com/elharo/gui/MainFrame.java:3: package com.elharo.math does not exist
import com.elharo.math.*;
^
src/com/elharo/gui/MainFrame.java:7: cannot find symbol
symbol : class Fraction
location: class com.elharo.gui.MainFrame
private Fraction f = new Fraction();
^
src/com/elharo/gui/MainFrame.java:7: cannot find symbol
symbol : class Fraction
location: class com.elharo.gui.MainFrame
private Fraction f = new Fraction();
^
3 errors
|
出現(xiàn)清單 2 中的錯(cuò)誤的原因是,雖然 javac 知道到何處可以找到 MainFrame.java,但它卻并不知道到何處可以找到 Fraction.java(您可能覺(jué)得它應(yīng)該具備足夠的智能來(lái)識(shí)別匹配的層次結(jié)構(gòu),但事實(shí)并非如此)。為了給它提供一些線索,必須指定源路徑。用源路徑指定編譯器應(yīng)該到哪些目錄查找源文件的層次結(jié)構(gòu)。在清單 2 中,源路徑是 src。所以我使用了 -sourcepath 選項(xiàng),如下所示:
$ javac -d bin -sourcepath src src/com/elharo/gui/MainFrame.java
|
現(xiàn)在再編譯程序,就不會(huì)出現(xiàn)錯(cuò)誤,并會(huì)產(chǎn)生如圖 5 所示的輸出。請(qǐng)注意 javac 也編譯了文件 Fraction.java,F(xiàn)raction.java 被當(dāng)前編譯的文件引用。
圖 4. 多類輸出
在源路徑中編譯多個(gè)目錄
在源路徑中可以有多個(gè)目錄,使用冒號(hào)分隔各目錄,但通常沒(méi)有必要這么做。例如,若我想包括本地的 src 目錄和用來(lái)存放另一個(gè)項(xiàng)目的源代碼的 /Users/elharo/Projects/XOM/src 目錄,我可以這樣進(jìn)行編譯:
$ javac -d bin -sourcepath src:/Users/elharo/Projects/XOM/src
src/com/elharo/gui/MainFrame.java
|
該命令并不編譯在這兩個(gè)層次結(jié)構(gòu)中所找到的每個(gè)文件。它只編譯由單個(gè)的 .java 文件直接或間接引用的文件,而此 .java 文件必須被編譯。
更常見(jiàn)的情況是,為 .java 文件用一個(gè)單一的源目錄,為類或放置了預(yù)編譯的第三方庫(kù)的 JAR 歸檔文件用多個(gè)目錄。而這正是類路徑的作用所在。
設(shè)置類路徑
在大中型項(xiàng)目中,每次都要對(duì)每個(gè)文件進(jìn)行重編譯會(huì)非常耗時(shí)。為減少這種編譯負(fù)擔(dān),可以在不同的 bin 目錄分別編譯和存儲(chǔ)相同項(xiàng)目的獨(dú)立部分。這些目錄被添加到類路徑。
將類添加到類路徑有幾種方法可選。但您只能使用 -classpath 命令行開關(guān)。例如,假設(shè)我想從另一個(gè)之前已經(jīng)編譯到目錄 /Users/elharo/classes 的工程導(dǎo)入文件,那么我會(huì)向命令行添加 -classpath /Users/elharo/classes,如下所示:
$ javac -d bin -sourcepath src -classpath /Users/elharo/classes
src/com/elharo/gui/MainFrame.java
|
現(xiàn)在假設(shè)需要添加兩個(gè)目錄,/Users/elharo/project1/classes 和 /Users/elharo/project2/classes。那么我將包含它們并使用冒號(hào)將它們分隔開,如下所示:
$ javac -d bin -sourcepath src
-classpath /Users/elharo/project1/classes:/Users/elharo/project2/classes
src/com/elharo/gui/MainFrame.java
|
 |
頂級(jí)目錄 請(qǐng)注意這里所說(shuō)的頂級(jí)目錄是指所有包含包的層次結(jié)構(gòu)的頂級(jí)目錄,包括 com/elharo/foo/bar 或 nu/xom/util 的層次結(jié)構(gòu)。具有匹配包名稱(com、elharo、math 等)的目錄絕不會(huì)直接包括在源路徑或類路徑中。 |
|
當(dāng)然,您也可以使用自己喜歡的各種相對(duì)路徑的格式。比如,如果 project1 和 project2 是當(dāng)前工作目錄的同級(jí)目錄(即它們有相同的父目錄),那么我會(huì)這樣引用它們:
$ javac -d bin -sourcepath src
-classpath ../project1/classes:../project2/classes
src/com/elharo/gui/MainFrame.java
|
到目前為止,我都一直假設(shè)程序完全獨(dú)立并且沒(méi)有使用任何單獨(dú)的編譯后的第三方庫(kù)。如果需要使用第三方庫(kù),還必須將它們也添加到類路徑。庫(kù)通常是 JAR 文件的格式,比如 junit.jar 或 icu4j.jar。在本例中,需要向類路徑添加的只是 JAR 文件本身,而不是包含 JAR 文件的目錄(從實(shí)質(zhì)上講,JAR 文件可以充當(dāng)包含編譯后的 .class 文件的一種目錄)。例如,如下命令會(huì)向類路徑添加三項(xiàng)內(nèi)容:/Users/elharo/classes 目錄,當(dāng)前工作目錄里的 icu4j.jar 文件和 /Users/elharo/lib 下的 junit.jar 文件:
$ javac -d bin -sourcepath src
-classpath /Users/elharo/classes:icu4j.jar:/Users/elharo/lib/junit.jar
src/com/elharo/gui/MainFrame.java
|
JAR 文件僅用于 .class 文件和其類路徑,不用于 .java 文件及其源路徑。
運(yùn)行程序
現(xiàn)在您已經(jīng)成功地編譯了程序,可以運(yùn)行它了。運(yùn)行與編譯相似但更為簡(jiǎn)單一些。當(dāng)運(yùn)行程序時(shí),只需指定兩項(xiàng)內(nèi)容:
- 類路徑。
- 包含
main() 方法的類的完全限定包名。
無(wú)需指定源路徑。
通常這里的類路徑與編譯程序所使用的類路徑相同,只是多了一個(gè)放置編譯后的輸出的目錄。例如,如果編譯命令如下所示:
$ javac -d bin -sourcepath src
-classpath /Users/elharo/classes:/Users/elharo/lib/junit.jar
src/com/elharo/gui/MainFrame.java
|
并且 main() 方法在 com.elharo.gui.Mainframe.java 類內(nèi),就可以像這樣運(yùn)行此程序:
$ java
-classpath /Users/elharo/classes:/Users/elharo/lib/junit.jar
com.elharo.gui.MainFrame
|
請(qǐng)務(wù)必注意命令行的最后一項(xiàng)是類名。它不是一個(gè)文件名,也不是 .java 或 .class。該類必須能夠在類路徑的某處找到。
可能存在類的其他地方
我強(qiáng)烈建議您在編譯和運(yùn)行時(shí)總是顯式地指定類路徑。也可以將文件放到其他地方,以便它們可以被添加到類路徑中,并被 javac 編譯器和 java 解釋器找到。這種做法會(huì)節(jié)省一些鍵入操作,但當(dāng)(注意不是如果)您無(wú)意間將一個(gè)舊版本的類放到類路徑中時(shí),這卻會(huì)耗費(fèi)大量的調(diào)試時(shí)間。
在本節(jié),將展示類常常隱匿其中的幾個(gè)地點(diǎn),這些類很可能會(huì)出乎意料地冒到類路徑中并導(dǎo)致問(wèn)題的出現(xiàn)。在不受您控制的機(jī)器上(比如服務(wù)器),這更為多見(jiàn)。
當(dāng)前的工作目錄
編譯器總是將當(dāng)前工作目錄 (.) 添加到類路徑,而不管您是否曾顯式地要求這樣做。您很容易忘記在和您所在的目錄相同的目錄中有和沒(méi)有的內(nèi)容。因此,請(qǐng)盡量避免將任何類或?qū)哟谓Y(jié)構(gòu)放入 project 或 home 目錄。相反地,應(yīng)該將 .java 文件和 .class 文件分別放入 src 目錄和 bin 目錄。
CLASSPATH
過(guò)一會(huì),您就會(huì)發(fā)現(xiàn)向類路徑手工添加 bin 目錄和 JAR 歸檔文件太過(guò)繁瑣。這時(shí)您可能會(huì)想要使用 CLASSPATH 環(huán)境變量。可以只向 CLASSPATH 環(huán)境變量添加一次目錄和 JAR 歸檔文件,之后就不需要在每次運(yùn)行 javac 或 java 時(shí)都要再鍵入這些路徑。
請(qǐng)務(wù)必抵制這種誘惑。這樣做,一旦加載了錯(cuò)誤的類或錯(cuò)誤版本的類,就會(huì)出問(wèn)題。而且意外加載錯(cuò)誤的類所帶來(lái)的調(diào)試時(shí)間常常會(huì)百倍于省下的那點(diǎn)鍵入時(shí)間。要避免輸入并自動(dòng)處理類路徑有更好的方法。
jre/lib/ext
jre/lib/ext 目錄中的 JAR 歸檔文件會(huì)被添加到通過(guò)虛擬機(jī)運(yùn)行的所有應(yīng)用程序的類路徑。這看起來(lái)很方便,實(shí)際上它與向 CLASSPATH 環(huán)境變量添加目錄一樣,存在長(zhǎng)遠(yuǎn)的潛在問(wèn)題。您遲早(通常很快)會(huì)在您想都想不到的地方加載類的一個(gè)錯(cuò)誤版本的類并會(huì)為此付出大量的調(diào)試時(shí)間。
部署一個(gè)服務(wù)器端的應(yīng)用程序時(shí),問(wèn)題就更為嚴(yán)峻。請(qǐng)確保部署到的服務(wù)器在其 jre/lib/ext 目錄沒(méi)有任何額外的 JAR。如果您不熟悉錯(cuò)誤癥狀,也不知道該如何查找,那么由類路徑中的錯(cuò)誤版本的 JAV 歸檔文件所帶來(lái)的問(wèn)題可能會(huì)非常難于調(diào)試。為了避免這些問(wèn)題的出現(xiàn),一些框架甚至編寫了自己的類加載器,用來(lái)繞過(guò) Java 代碼通常的類加載機(jī)制。
jre/lib/endorsed
jre/lib/endorsed 目錄里的 JAR 文件 也被添加到了通過(guò)虛擬機(jī)運(yùn)行的所有應(yīng)用程序的類路徑。不同的是,這里的文件被實(shí)際放入了 bootclasspath 而不是通常的類路徑,并可以代替 JDK 附帶的標(biāo)準(zhǔn)類。這種方式對(duì)于在 VM 更新 XML 解析器和修復(fù) bug 尤其有用。
但是,如前所述,這種方法看起來(lái)十分方便,但實(shí)際上也存在長(zhǎng)期的潛在問(wèn)題,原因也一樣。如果需要替換 JDK 類,可以在運(yùn)行時(shí)使用 -Xbootclasspath/p 選項(xiàng)來(lái)避免意外地加載錯(cuò)誤版本的類。
$ java -classpath /Users/elharo/classes
-Xbootclasspath/p:xercesImpl.jar com.elharo.gui.MainFrame
|
自動(dòng)管理類路徑
在想要使用電動(dòng)射釘槍之前要先熟練使用錘子,與此相似,在試圖采用更強(qiáng)大的自動(dòng)管理工具之前也要先能自如地手動(dòng)管理這些類。如果您掌握了命令行工具集,就可以使用另外的工具來(lái)自動(dòng)處理源路徑和類路徑所需的一些繁瑣過(guò)程。這些工具大部分也需要您像本文所介紹的那樣組織文件。
IDE
像 Eclipse 和 NetBeansMost 這樣的許多開發(fā)環(huán)境都能協(xié)助類路徑的自動(dòng)管理。例如,當(dāng)更改包的名稱時(shí),Eclipse 能相應(yīng)地移動(dòng)對(duì)應(yīng)的 .java 文件,如圖 5 所示:
圖 5. 在 Eclipse 中快速修復(fù)類路徑
請(qǐng)記住,這些 IDE 位于文件系統(tǒng)的頂部,必須正確設(shè)置,尤其是當(dāng)需要與其他工具和其他 IDE 集成時(shí)就更應(yīng)如此。這些工具最大的貢獻(xiàn)是用 GUI 對(duì)話框、樹視圖和選項(xiàng)卡代替了命令行開關(guān)參數(shù),但其基本的文件結(jié)構(gòu)還是一樣的。
Ant
Ant 是自動(dòng)化構(gòu)建過(guò)程的事實(shí)上的標(biāo)準(zhǔn)工具。與將目錄放在 jre/lib/ext 或 CLASSPATH 環(huán)境變量的做法不同,Ant 真的可以讓您創(chuàng)建單步的構(gòu)建過(guò)程。但您仍然需要在 Ant build.xml 設(shè)置類路徑并手動(dòng)將源文件放到正確的目錄。但至少現(xiàn)在您無(wú)需在每次編譯都要重新進(jìn)行指定。
Maven
Maven 在組織和自動(dòng)化構(gòu)建過(guò)程方面比 Ant 還要更進(jìn)一步。Maven 提供一個(gè)合理的默認(rèn)設(shè)置讓您可以通過(guò)添加少許幾行代碼并將源文件放到 Maven 能夠找到的位置即可構(gòu)建簡(jiǎn)單的項(xiàng)目。您仍然需要調(diào)整文件系統(tǒng)和包的層次結(jié)構(gòu)。Maven 在管理第三方庫(kù)的依賴性方面也有上佳的表現(xiàn),雖然它不如 Ant 那么易于定制。
結(jié)束語(yǔ)
不管類路徑有多么棘手,您都可以通過(guò)一些簡(jiǎn)單的規(guī)則對(duì)它加以管制,尤其是要記住如下的一些原則:
- 將類放到包中。
- 嚴(yán)格遵守包和類的命名約定和大小寫約定。
- 確保包的層次結(jié)構(gòu)與目錄的層次結(jié)構(gòu)匹配。
- 總是對(duì) javac 應(yīng)用
-d 選項(xiàng)。
- 不要在 jre/lib/ext 內(nèi)放任何東西。
- 不要在 jre/lib/endorsed 內(nèi)放任何東西。
- 不要將 .java 文件與 .class 文件放在同一個(gè)目錄。
- 不要將任何 .java 或 .class 文件放在當(dāng)前的工作目錄。
最后一點(diǎn)提示:很多耗時(shí)的類路徑問(wèn)題的起因大都是目錄名拼寫錯(cuò)誤或從錯(cuò)誤目錄進(jìn)行了編譯。如果您不能找到問(wèn)題的所在,可以問(wèn)問(wèn)周圍的朋友或同事。以我的經(jīng)驗(yàn),自己發(fā)現(xiàn)自己的錯(cuò)誤總是困難的,但這些錯(cuò)誤在別人看來(lái)卻顯而易見(jiàn)。所以尋求他人的幫助也是一種切實(shí)有效的調(diào)試技巧。
類路徑確實(shí)不是個(gè)簡(jiǎn)單的問(wèn)題,但總會(huì)有相應(yīng)的應(yīng)對(duì)方法,所以它是完全可管理的。些許的謹(jǐn)慎加上對(duì)本文所介紹的命名約定、命令行參數(shù)和目錄結(jié)構(gòu)的注意,應(yīng)該能夠使您在問(wèn)題最少的情況下編譯和運(yùn)行程序了。
參考資料
學(xué)習(xí)
獲得產(chǎn)品和技術(shù)
- 下載 Ant:當(dāng)前 Apache 的頂級(jí)項(xiàng)目。
- 下載 Maven:Java 項(xiàng)目的 Apache 構(gòu)建管理器。
討論
關(guān)于作者
 |
|

|
 |
Elliotte Rusty Harold 來(lái)自新奧爾良,現(xiàn)在他還定期回老家喝一碗美味的秋葵湯。不過(guò)目前,他和妻子 Beth 定居在紐約臨近布魯克林的 Prospect Heights,同住的還有他的貓咪 Charm(取自夸克)和 Marjorie(取自他岳母的名字)。他是 Polytechnic 大學(xué)計(jì)算機(jī)科學(xué)的副教授,他在該校講授 Java 和面向?qū)ο缶幊?。他?Web 站點(diǎn) Cafe au Lait 已經(jīng)成為 Internet 上最流行的獨(dú)立 Java 站點(diǎn)之一,它的姊妹站點(diǎn) Cafe con Leche 已經(jīng)成為最流行的 XML 站點(diǎn)之一。 他最近編著的一本書是 Java I/O, 2nd edition。他目前在從事處理 XML 的 XOM API、Jaxen XPath 引擎和 Jester 測(cè)試覆蓋率工具的開發(fā)工作。
|
|