Java很誘人,但對(duì)于剛跨入Java門(mén)檻的初學(xué)者來(lái)說(shuō),編譯并運(yùn)行一個(gè)無(wú)比簡(jiǎn)單的Java程序簡(jiǎn)直就是一個(gè)惡夢(mèng)。明明程序沒(méi)錯(cuò),但各種各樣讓人摸不著頭腦的錯(cuò)誤信息真的讓你百思不得其解,許多在Java門(mén)口徘徊了很久的初學(xué)者就這樣放棄了學(xué)習(xí)Java的機(jī)會(huì),很是可惜。筆者也經(jīng)歷過(guò)這個(gè)無(wú)比痛苦的階段,感覺(jué)到編譯難的問(wèn)題就出在classpath的設(shè)置及對(duì)package的理解之上。本文以實(shí)例的方式,逐一解決在編譯過(guò)程中所出現(xiàn)的各種classpath的設(shè)置問(wèn)題。本文實(shí)例運(yùn)行的環(huán)境是在Windows?XP?+?JDK?1.5.0。對(duì)其他的環(huán)境,讀者應(yīng)該很容易進(jìn)行相應(yīng)的轉(zhuǎn)換。

1.?下載并安裝JDK1.5.0,并按默認(rèn)路徑,安裝到C:\Program?Files\Java\jdk1.5.0中。

2.?用鼠標(biāo)單擊WindowsXP的“開(kāi)始”->“運(yùn)行”,在彈出的運(yùn)行窗口中輸入cmd,按確定或回車(chē),打開(kāi)一個(gè)命令行窗口。

3.?在命令行中輸入:

java

有一列長(zhǎng)長(zhǎng)的洋文滾了出來(lái),這是JDK告訴我們java這個(gè)命令的使用方法。其中隱含了一個(gè)重要信息,即JDK安裝成功,可以在命令行中使用java此命令了。

4.?在命令行中輸入

javac

屏幕顯示:

'javac'?不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件。

這是由于windows找不到j(luò)avac這個(gè)命令的原因。這就不明白了,java與javac都是JDK在同一個(gè)子目錄里面的兩個(gè)文件,為什么可以直接運(yùn)行java而不能直接運(yùn)行javac呢?原來(lái),Sun公司為了方便大家在安裝完JDK后馬上就可以運(yùn)行Java類(lèi)文件,在后臺(tái)悄悄地將java命令加入了Path的搜索路徑中,因此我們可以直接運(yùn)行java命令(但我們是看不到它到底是在哪設(shè)置的,無(wú)論是在用戶的Path或系統(tǒng)的Path設(shè)置中均找不到這個(gè)java存放的路徑)。但Sun所做的到此為止,其他JDK的命令,一概不管,需要由用戶自己添加到搜索路徑中。

5.?既然如此,那我們自己添加Path的搜索路徑吧。對(duì)“我的電腦”按右鍵,選“屬性”,在“系統(tǒng)屬性”窗口中選“高級(jí)”標(biāo)簽,再按“環(huán)境變量”按鈕,彈出一個(gè)“環(huán)境變量”的窗口,在用戶變量中新建一個(gè)變量,變量名為“Path”,變量值為"C:\Program?Files\Java\jdk1.5.0\bin;%PATH%"。最后的%PATH%的意思是說(shuō),保留原有的Path設(shè)置,且將目前的Path設(shè)置新加到其前面。一路按“確定”退出(共有3次)。關(guān)掉原來(lái)的命令行窗口,依照第2步,重新打開(kāi)一個(gè)新的命令行窗口。在此窗口中輸入

javac

長(zhǎng)長(zhǎng)的洋文又出現(xiàn)了,這回是介紹javac的用法。設(shè)置成功。

6.?So?far?so?good.?到目前為止,我們已經(jīng)可以編程了。但是,這不是一個(gè)好辦法。因?yàn)殡S著以后我們深入學(xué)習(xí)Java,我們就會(huì)用到JUnit、Ant或NetBeans等應(yīng)用工具,這些工具在安裝時(shí),都需要一個(gè)名為指向JDK路徑的“JAVA_HOME”的環(huán)境變量,否則就安裝不了。因此,我們需要改進(jìn)第5步,為以后作好準(zhǔn)備。依照第5步,彈出“環(huán)境變量”的窗口,在用戶變量中新建一個(gè)變量,變量名為“JAVA_HOME”,變量值為"C:\Program?Files\Java\jdk1.5.0"。注意,這里的變量值只到j(luò)dk1.5.0,不能延伸到bin中。確定后,返回“環(huán)境變量”的窗口,雙擊我們?cè)仍O(shè)定的Path變量,將其值修改為“%JAVA_HOME%\bin;%PATH%”。這種效果與第5步是完全一樣的,只不過(guò)多了一個(gè)JAVA_HOME的變量。這樣,以后當(dāng)我們需要指向JDK的路徑時(shí),只需要加入“%JAVA_HOME%”就行了。至此,Path路徑全部設(shè)置完畢。一路確定退出,打開(kāi)新的命令行窗口,輸入

javac

如果長(zhǎng)長(zhǎng)的洋文出現(xiàn),Path已經(jīng)設(shè)置正確,一切正常。如果不是,請(qǐng)仔細(xì)檢查本步驟是否完全設(shè)置正確。

7.?開(kāi)始編程。在C盤(pán)的根目錄中新建一個(gè)子目錄,名為“JavaTest”,以作為存放Java源代碼的地方。打開(kāi)XP中的記事本,先將其保存到JavaTest文件夾中,在“文件名”文本框中輸入"Hello.java"。注意,在文件名的前后各加上一個(gè)雙引號(hào),否則,記事本就會(huì)將其存為"Hello.java.txt"的文本文件。然后輸入以下代碼:

public?class?Hello?{
??public?static?void?main(String[]?args)?{
????System.out.println("Hello,?world");
??}
}

再次保存文件。

8.?在命令行窗口中輸入

cd?C:\JavaTest

將當(dāng)前路徑轉(zhuǎn)入JavaTest中。然后,輸入

javac?Hello.java

JDK就在JavaTest文件夾中編譯生成一個(gè)Hello.class的類(lèi)文件。如果出現(xiàn)“1?error”或“XX?errors”的字樣,說(shuō)明是源代碼的輸入有誤,請(qǐng)根據(jù)出錯(cuò)提示,仔細(xì)地按第7步的代碼找出并修正錯(cuò)誤。請(qǐng)讀者注意甄別代碼輸入有誤的問(wèn)題與classpath設(shè)置有誤的問(wèn)題。因?yàn)楸疚氖顷P(guān)于如何正確設(shè)置classpath及package的,因此,這里假設(shè)讀者輸入的代碼準(zhǔn)確無(wú)誤。到目前為此,由于我們是在源代碼的當(dāng)前路徑下編譯,因此,不會(huì)出現(xiàn)classpath設(shè)置有誤的問(wèn)題。

9.?在命令行窗口中輸入

java?Hello

屏幕出現(xiàn)了

Hello?world

成功了,我們已經(jīng)順利地編譯及運(yùn)行了第一個(gè)Java程序。
但是,第8步及第9步是不完美的,因?yàn)槲覀兪窃贘avaTest這個(gè)存放源碼的文件夾中進(jìn)行編譯及運(yùn)行的,因此,一些非常重要的問(wèn)題并沒(méi)有暴露出來(lái)。實(shí)際上,第8步的“javac?Hello.java”及第9步的“java?Hello”涉及到兩個(gè)問(wèn)題,一是操作系統(tǒng)如何尋找“javac”及“java”等命令,二是操作系統(tǒng)如何尋找“Hello.java”及“Hello.class”這些用戶自己創(chuàng)建的文件。對(duì)于“javac”及“java”等命令,由于它們均是可執(zhí)行文件,操作系統(tǒng)就會(huì)依據(jù)我們?cè)诘?步中設(shè)置好的Path路徑中去尋找。而對(duì)于“Hello.java”及“Hello.class”這些文件,Path的設(shè)置不起作用。由于我們是在當(dāng)前工作路徑中工作,java及javac會(huì)在當(dāng)前工作路徑中尋找相應(yīng)的java文件(class文件的尋找比較特殊,詳見(jiàn)第11步),
因此一切正常。下面我們開(kāi)始人為地將問(wèn)題復(fù)雜化,在非當(dāng)前工作路徑中編譯及運(yùn)行,看看結(jié)果如何。

10.?在命令行窗口中輸入

cd?C:
轉(zhuǎn)入到C盤(pán)根目錄上,當(dāng)前路徑離開(kāi)了存放源碼的工作區(qū)。輸入

javac?Hello.java

屏幕出現(xiàn):

error:?cannot?read:?Hello.java
1?error

找不到Hello.java了。我們要給它指定一個(gè)路徑,告訴它到C:\JavaTest去找Hello.java文件。輸入

javac?C:\JavaTest\Hello.java

OK,這回不報(bào)錯(cuò)了,編譯成功。

11.?輸入

java?C:\JavaTest\Hello

這回屏幕出現(xiàn):

Exception?in?thread?"main"?java.lang.NoClassDefFoundError:?C:\JavaTest\Hello

意思為在“C:\JavaTest\Hello”找不到類(lèi)的定義。明明C:\JavaTest\Hello是一個(gè).class文件,為什么就找不到呢?原來(lái),Java對(duì)待.java文件與.class文件是有區(qū)別的。對(duì).java文件可以直接指定路徑給它,而java命令所需的.class文件不能出現(xiàn)擴(kuò)展名,也不能指定額外的路徑給它。

那么,如何指定路徑呢?對(duì)于Java所需的.class文件,必須通過(guò)classpath來(lái)指定。

12.?依照第5步,彈出“環(huán)境變量”窗口,在用戶變量中新建一個(gè)變量,變量名為“classpath”,變量值為"C:\JavaTest"。一路按“確定”退出。關(guān)閉原命令行窗口,打開(kāi)新的命令行窗口,輸入

java?Hello

“Hello?world”出來(lái)了。由此可見(jiàn),在“環(huán)境變量”窗口中設(shè)置classpath的目的就是告訴JDK,到哪里去尋找.class文件。這種方法一旦設(shè)置好,以后每次運(yùn)行java或javac時(shí),在需要調(diào)用.class文件時(shí),JDK都會(huì)自動(dòng)地來(lái)到這里尋找。因此,這是一個(gè)全局性的設(shè)置。

13.?除了這種在環(huán)境變量”窗口中設(shè)置classpath的方法之外,還有另一種方法,即在java命令后面加上一個(gè)選項(xiàng)classpath,緊跟著不帶擴(kuò)展名的class文件名。例如,

java?-classpath?C:\JavaTest?Hello

JDK遇到這種情況時(shí),先根據(jù)命令行中的classpath選項(xiàng)中指定的路徑去尋找.class文件,找不到時(shí)再到全局的classpath環(huán)境變量中去尋找。這種情況下,即使是沒(méi)有設(shè)置全局的classpath環(huán)境變量,由于已經(jīng)在命令行中正確地指定類(lèi)路徑,也可以運(yùn)行。

為了在下面的例子中更好地演示classpath的問(wèn)題,我們先將全局的classpath環(huán)境變量刪除,而在必要時(shí)代之以命令行選項(xiàng)-classpath。彈出“環(huán)境變量”窗口,選中“classpath”的變量名,按“刪除”鍵。

此外,java命令中還可以用cp,即classpath的縮寫(xiě)來(lái)代替classpath,如java?-cp?C:\JavaTest?Hello。特別注意的是,JDK?1.5.0之前,javac命令不能用cp來(lái)代替classpath,而只能用classpath。而在JDK?1.5.0中,java及javac都可以使用cp及classpath。因此,為保持一致,建議一概使用classpath作為選項(xiàng)名稱(chēng)。

14.?我們?cè)俅稳藶榈貜?fù)雜化問(wèn)題。關(guān)閉正在編輯Hello.java的記事本,然后將JavaTest文件夾名稱(chēng)改為帶空格的“Java?Test”。在命令行中輸入

javac?C:\Java?Test\Hello.java

長(zhǎng)長(zhǎng)的洋文又出來(lái)了,但這回卻是報(bào)錯(cuò)了:

javac:?invalid?flag:?C:\Java

JDK將帶有空格的C:\Java?Test分隔為兩部分"C:\Java"及"Test\Hello.java",并將C:\Java視作為一個(gè)無(wú)效的選項(xiàng)了。這種情況下,我們需要將整個(gè)路徑都加上雙引號(hào),即

javac?"C:\Java?Test\Hello.java"

這回JDK知道,引號(hào)里面的是一個(gè)完整的路徑,因此就不會(huì)報(bào)錯(cuò)了。同樣,對(duì)java命令也需要如此,即

java?-classpath?"C:\Java?Test"?Hello

對(duì)于長(zhǎng)文件名及中文的文件夾,XP下面可以不加雙引號(hào)。但一般來(lái)說(shuō),加雙引號(hào)不容易出錯(cuò),也容易理解,因此,建議在classpath選項(xiàng)中使用雙引號(hào)。

15.?我們?cè)賮?lái)看.java文件使用了其他類(lèi)的情況。在C:\Java?Test中新建一個(gè)Person.java文件,內(nèi)容如下:

public?class?Person?{
??private?String?name;

??public?Person(String?name)?{
????this.name?=?name;
??}

??public?String?getName()?{
????return?name;
??}
}

然后,修改Hello.java,內(nèi)容如下:

public?class?Hello?{
??public?static?void?main(String[]?args)?{
????Person?person?=?new?Person("Mike");
????System.out.println(person.getName());
??}
}

在命令行輸入

javac?"C:\Java?Test\Hello.java"

錯(cuò)誤來(lái)了:

C:\Java?Test\Hello.java:3:?cannot?find?symbol
symbol:?class?Person

JDK提示找不到Person類(lèi)。為什么javac?"C:\Java?Test\Hello.java"在第14步中可行,而在這里卻不行了呢?第14步中的Hello.java文件并沒(méi)有用來(lái)其他類(lèi),因此,JDK不需要去尋找其他類(lèi),而到了這里,我們修改了Hello.java,讓其使用了一個(gè)Person類(lèi)。根據(jù)第11步,我們需要告訴JDK,到哪里去找所用到的類(lèi),即使這個(gè)被使用的類(lèi)就與Hello.java一起,同在C:\Java?Test下面!輸入

javac?-classpath?"C:\Java?Test"?"C:\Java?Test\Hello.java"

編譯通過(guò),JDK在C:\Java?Test文件夾下同時(shí)生成了Hello.class及Person.class兩個(gè)文件。實(shí)際上,由于Hello.java使用了Person.java類(lèi),JDK先編譯生成了Person.class,然后再編譯生成Hello.class。因此,不管Hello.java這個(gè)主類(lèi)使用了多少個(gè)其他類(lèi),只要編譯這個(gè)類(lèi),JDK就會(huì)自動(dòng)編譯其他類(lèi),很方便。輸入

java?-classpath?"C:\Java?Test"?Hello

屏幕出現(xiàn)了

Mike

成功。

16.?第15步說(shuō)明了在Hello.java中如何使用一個(gè)我們自己創(chuàng)建的Person.java,而且這個(gè)類(lèi)與Hello.java是同在一個(gè)文件夾下。在這一步中,我們將考查Person.java如果放在不同文件夾下面的情況。

先將C:\Java?Test文件夾下的Person.class文件刪除,然后在C:\Java?Test文件夾下新建一個(gè)名為DF的文件夾,并將C:\Java?Test文件夾下的Person.java移動(dòng)到其下面。在命令行輸入

javac?-classpath?"C:\Java?Test\DF"?"C:\Java?Test\Hello.java"

編譯通過(guò)。這時(shí)javac命令沒(méi)有什么不同,只需將classpath改成C:\Java?Test\DF就行了。

在命令行輸入

java?-classpath?"C:\Java?Test"?Hello

這時(shí)由于Java需要找在不同文件夾下的兩個(gè).class文件,而命令行中只告訴JDK一個(gè)路徑,即C:\Java?Test,在此文件夾下,只能找到Hello.class,找不到Person.class文件,因此,錯(cuò)誤是可以預(yù)料得到的:

Exception?in?thread?"main"?java.lang.NoClassDefFoundError:?Person
????????at?Hello.main(Hello.java:3)

果真找不到Person.class。在設(shè)置兩個(gè)以上的classpath時(shí),先將每個(gè)路徑以雙引號(hào)引起來(lái),再將這些路徑以“;”號(hào)隔開(kāi),并且每個(gè)路徑與“;”之間不能帶有空格。因此,我們?cè)诿钚兄匦螺斎耄?br />
java?-classpath?"C:\Java?Test";"C:\Java?Test\DF"?Hello

編譯成功。但也暴露出一個(gè)問(wèn)題,如果我們需要用到許多分處于不同文件夾下的類(lèi),那這個(gè)classpath的設(shè)置豈不是很長(zhǎng)!有沒(méi)有辦法,對(duì)于一個(gè)文件夾下的所有.class文件,只指定這個(gè)文件夾的classpath,然后讓JDK自動(dòng)搜索此文件夾下面所有相應(yīng)的路徑?有,只要使用package。

17.?package簡(jiǎn)介。Java中引入package的概念,主要是為了解決命名沖突的問(wèn)題。比如說(shuō),在我們的例子中,我們?cè)O(shè)計(jì)了一個(gè)很簡(jiǎn)單的Person類(lèi),如果某人開(kāi)發(fā)了一個(gè)類(lèi)庫(kù),其中恰巧也有一個(gè)Person類(lèi),當(dāng)我們使用這個(gè)類(lèi)庫(kù)時(shí),兩個(gè)Person類(lèi)出現(xiàn)了命名沖突,JDK不知道我們到底要使用哪個(gè)Person類(lèi)。更有甚者,當(dāng)我們也開(kāi)發(fā)了一個(gè)很龐大的類(lèi)庫(kù),無(wú)可避免地,我們的類(lèi)庫(kù)中與其他人開(kāi)發(fā)的類(lèi)庫(kù)中命名沖突的情況就會(huì)越來(lái)越多。總不能為了避免自己的類(lèi)名與其他人開(kāi)發(fā)的類(lèi)名相同,而讓每個(gè)編程人員都絞盡腦汁地將一個(gè)本應(yīng)叫Writer的類(lèi)強(qiáng)行改名為SarkuyaWriter,MikeWriter,?SmithWriter吧?

現(xiàn)實(shí)生活中也是如此。假如你名叫張三,又假如與你同一單位的人中有好幾個(gè)都叫張三,那你的問(wèn)題就來(lái)了。某天單位領(lǐng)導(dǎo)在會(huì)上宣布,張三被任命為辦公室主任,你簡(jiǎn)直不知道是該哭還是該笑。但如果你的單位中只有你叫張三,你才不會(huì)在乎全國(guó)叫張三的人有多少個(gè),因?yàn)槠渌麖埲挤植荚谌珖?guó)各地、其他城市,你看不見(jiàn)他們,摸不著他們,自然不會(huì)擔(dān)心。

Sun從這個(gè)“張三問(wèn)題”受到了很大的啟發(fā),為解決命名沖突問(wèn)題,就采取了“眼不見(jiàn)心不煩”的策略:將每個(gè)類(lèi)都?xì)w屬到一個(gè)特定的區(qū)域中,在同一個(gè)區(qū)域中的所有類(lèi),都不允許同名;而不同區(qū)域的類(lèi),由于相互看不到,則允許有同名的類(lèi)存在。這樣,就解決了命名沖突的問(wèn)題,正如北京的張三與上海的張三畢竟不是同一人。這個(gè)區(qū)域在Java中就叫package。由于package在Java中非常重要,如果你沒(méi)有定義自己的package,JDK將會(huì)你的類(lèi)都?xì)w到一個(gè)默認(rèn)的無(wú)名package中。

自定義package的名稱(chēng)可以由各個(gè)程序員自由創(chuàng)建。作為避免命名沖突的手段,package的名稱(chēng)最好足以與其他程序員的區(qū)別開(kāi)來(lái)。在互聯(lián)網(wǎng)上,每個(gè)域名都是唯一的,因此,Sun推薦將你自己的域名倒寫(xiě)后作為package的名稱(chēng)。如果你沒(méi)有自己的域名,很可能只是因?yàn)槟抑行邼蝗ド暾?qǐng)罷了,并不見(jiàn)得你假想的域名與其他域名發(fā)生沖突。例如,筆者假想的域名是sarkuya.com,目前就是唯一的,因此我的package就可以定名為com.sarkuya。謝謝Java給了我們一個(gè)免費(fèi)使用我們自己域名的機(jī)會(huì),唯一的前提是倒著寫(xiě)。當(dāng)然,每個(gè)package下面還可以帶有不同的子package,如com.sarkuya.util,com.sarkuya.swing,等等。

定義package的方式是在相應(yīng)的.java文件的第一行加上“package?packagename;”的字樣,而且每個(gè).java文件只能有一個(gè)package。實(shí)際上,Java中的package的實(shí)現(xiàn)是與計(jì)算機(jī)文件系統(tǒng)相結(jié)合的,即你有什么樣的package,在硬盤(pán)上就有什么樣的存放路徑。例如,某個(gè)類(lèi)的package名為com.sarkuya.util,那么,這個(gè)類(lèi)就應(yīng)該必須存放在com/sarkuya/util的路徑下面。至于這個(gè)com/sarkuya/util又是哪個(gè)文件夾的子路徑,第18步會(huì)談到。

package除了有避免命名沖突的問(wèn)題外,還引申出一個(gè)保護(hù)當(dāng)前package下所有類(lèi)文件的功能,主要通過(guò)為類(lèi)定義幾種可視度不同的修飾符來(lái)實(shí)現(xiàn):public,?protected,?private,?另外加上一個(gè)并不真實(shí)存在的friendly類(lèi)型。

對(duì)于冠以public的類(lèi)、類(lèi)屬變量及方法,包內(nèi)及包外的任何類(lèi)均可以訪問(wèn);
protected的類(lèi)、類(lèi)屬變量及方法,包內(nèi)的任何類(lèi),及包外的那些繼承了此類(lèi)的子類(lèi)才能訪問(wèn);
private的類(lèi)、類(lèi)屬變量及方法,包內(nèi)包外的任何類(lèi)均不能訪問(wèn);
如果一個(gè)類(lèi)、類(lèi)屬變量及方法不以這三種修飾符來(lái)修飾,它就是friendly類(lèi)型的,那么包內(nèi)的任何類(lèi)都可以訪問(wèn)它,而包外的任何類(lèi)都不能訪問(wèn)它(包括包外繼承了此類(lèi)的子類(lèi)),因此,這種類(lèi)、類(lèi)屬變量及方法對(duì)包內(nèi)的其他類(lèi)是友好的,開(kāi)放的,而對(duì)包外的其他類(lèi)是關(guān)閉的。

前面說(shuō)過(guò),package主要是為了解決命名沖突的問(wèn)題,因此,處在不同的包里面的類(lèi)根本不用擔(dān)心與其他包的類(lèi)名發(fā)生沖突,因?yàn)镴DK在默認(rèn)情況下只使用本包下面的類(lèi),對(duì)于其他包,JDK一概視而不見(jiàn):“眼不見(jiàn)心不煩”。如果要引用其他包的類(lèi),就必須通過(guò)import來(lái)引入其他包中相應(yīng)的類(lèi)。只有在這時(shí),JDK才會(huì)進(jìn)行進(jìn)一步的審查,即根據(jù)其他包中的這些類(lèi)、類(lèi)屬變量及方法的可視度來(lái)審查是否符合使用要求。如果此審查通不過(guò),編譯就此卡住,直至你放棄使用這些類(lèi)、類(lèi)屬變量及方法,或者將被引入的類(lèi)、類(lèi)屬變量及方法的修飾符改為符合要求為止。如果此審查通過(guò),JDK最后進(jìn)行命名是否沖突的審查。如果發(fā)現(xiàn)命名沖突,你可以通過(guò)在代碼中引用全名的方式來(lái)顯式地引用相應(yīng)的類(lèi),如使用

java.util.Date?=?new?java.util.Date()

或是

java.sql.Date?=?new?java.sql.Date()。

package的第三大作用是簡(jiǎn)化classpath的設(shè)置。還記得第16步中的障礙嗎?這里重新引用其java命令:

java?-classpath?"C:\Java?Test";"C:\Java?Test\DF"?Hello

我們必須將所有的.class文件的路徑一一告訴JDK,而不管DF其實(shí)就是C:\Java?Test的子目錄。如果要用到100個(gè)不同路徑的.class文件,我們就得將classpath設(shè)置為一個(gè)特別長(zhǎng)的字符串,很累。package的引入,很好地解決了這個(gè)問(wèn)題。package的與classpath相結(jié)合,通過(guò)import指令為中介,將原來(lái)必須由classpath完成的類(lèi)路徑搜索功能,很巧妙地轉(zhuǎn)移到import的身上,從而使classpath的設(shè)置簡(jiǎn)潔明了。我們先看下面的例子。

18.?先在Hello.java中導(dǎo)入DF.Person。代碼修改如下:

import?DF.Person;

public?class?Hello?{
??public?static?void?main(String[]?args)?{
????Person?person?=?new?Person("Mike");
????System.out.println(person.getName());
??}
}

再將DF子文件夾中的Person.java設(shè)置一個(gè)DF包。代碼修改如下:

package?DF;

public?class?Person?{
??private?String?name;
??public?Person(String?name)?{
????this.name?=?name;
??}

??public?String?getName()?{
????return?name;
??}
}

好了,神奇的命令行出現(xiàn)了:

javac?-classpath?"C:\Java?Test"?"C:\Java?Test\Hello.java"
java?-classpath?"C:\Java?Test"?Hello

盡管這次我們只設(shè)置了C:\Java?Test的classpath,但編譯及運(yùn)行居然都通過(guò)了!事實(shí)上,Java在搜索.class文件時(shí),共有三種方法:
一是全局性的設(shè)置,詳見(jiàn)第12步,其優(yōu)點(diǎn)是一次設(shè)置,每次使用;
二是在每次的javac及java命令行中自行設(shè)置classpath,這也是本文使用最多的一種方式,其優(yōu)點(diǎn)是不加重系統(tǒng)環(huán)境變量的負(fù)擔(dān);
三是根據(jù)import指令,將其內(nèi)容在后臺(tái)轉(zhuǎn)換為classpath。JDK將讀取全局的環(huán)境變量classpath及命令行中的classpath選項(xiàng)信息,然后將每條classpath與經(jīng)過(guò)轉(zhuǎn)換為路徑形式的import的內(nèi)容相合并,從而形成最終的classpath.?在我們的例子中,JDK讀取全局的環(huán)境變量classpath及命令行中的classpath選項(xiàng)信息,得到C:\Java?Test。接著,將import?DF.Person中的內(nèi)容,即DF.Person轉(zhuǎn)換為DF\Person,?然后將C:\Java?Test與其合并,成為C:\Java?Test\DF\Person,這就是我們所需要的Person.class的路徑。在Hello.java中有多少條import語(yǔ)句,就自動(dòng)進(jìn)行多少次這樣的轉(zhuǎn)換。而我們?cè)诿钚兄兄恍韪嬖VJDK最頂層的classpath就行了,剩下的則由各個(gè)類(lèi)中的import指令代為操勞了。這種移花接木的作法為我們?cè)诿钚兄惺止さ卦O(shè)置classpath提供了極大的便利。

應(yīng)注意的一點(diǎn)是,import指令是與package配套使用的,只有在某類(lèi)通過(guò)“package?pacakgename;”設(shè)定了包名后,才能給其他類(lèi)通過(guò)import指令導(dǎo)入。如果import試圖導(dǎo)入一個(gè)尚未設(shè)置包的類(lèi),JVM就會(huì)報(bào)錯(cuò)。

19.?我們接下來(lái)看,當(dāng)使用JDK類(lèi)庫(kù)時(shí),classpath如何設(shè)置。

20.?修改Hello.java,內(nèi)容如下:

import?DF.Person;
import?java.util.Date;

public?class?Hello?{
??public?static?void?main(String[]?args)?{
????Date?date?=?new?Date();
????System.out.println(date);

????Person?person?=?new?Person("Mike");
????System.out.println(person.getName());
??}
}

21.?JDK類(lèi)庫(kù)存放于C:\Program?Files\Java\jdk1.5.0\jre\lib\rt.jar文件中。關(guān)于jar文件的介紹,已經(jīng)超出了本文的范圍,感興趣的讀者可以閱讀Horstmann寫(xiě)的Core?Java一書(shū)。

jar文件可以用WinRar打開(kāi)。用WinRar打開(kāi)后,可以看到里面有一些文件夾,雙擊其中的java文件夾,再雙擊util的文件夾,可以在看到Date.class文件就在其中。如果你看過(guò)Data.java或其他JDK類(lèi)庫(kù)的源碼(在C:\Program?Files\Java\jdk1.5.0\src.zip文件中),你就會(huì)發(fā)現(xiàn),像java、util這些文件夾均是package。這也是Hello.java第2行中使用了import指令的原因。

我們可以通過(guò)WinRar的查找功能來(lái)定位某個(gè)類(lèi)所在的包。在“查找文件”的窗口中的“要查找的文件名”文本框中輸入Date.class,就會(huì)查找出在rt.jar文件中存在兩個(gè)Date.class文件,一個(gè)是java\sql\Date.class,另一個(gè)是java\util\Date.class。其中,sql下面的Date.class文件與數(shù)據(jù)庫(kù)有關(guān),并非我們這里所需,java\util\Date.class才是我們所要的。

rt.jar文件就像本文中的C:\Java?Test中一樣,是JDK類(lèi)庫(kù)的唯一入口。我們可以在命令行的classpath選項(xiàng)指定.jar文件。需要注意,.jar文件的classpath設(shè)置有些特珠。在以前的例子中,我們?cè)O(shè)置classpath時(shí)都是設(shè)置了路徑就行了,而對(duì)于.jar文件,我們必須將.jar文件名直接加到classpath中。

22.?在命令行輸入

javac?-classpath?"C:\Program?Files\Java\jdk1.5.0\jre\lib\rt.jar";"C:\Java?Test"?"C:\Java?Test\Hello.java"
java?-classpath?"C:\Program?Files\Java\jdk1.5.0\jre\lib\rt.jar";"C:\Java?Test"?Hello

這樣當(dāng)然沒(méi)有問(wèn)題,因?yàn)槲覀冎付藃t.jar文件及C:\Java?Test兩個(gè)classpath。但且慢,在命令行輸入:

javac?-classpath?"C:\Java?Test"?"C:\Java?Test\Hello.java"
java?-classpath?"C:\Java?Test"?Hello

不可思議的是,編譯及運(yùn)行成功了!令人驚訝的是在我們將classspath只設(shè)置為C:\Java?Test的情況下,JDK如何得出java.util.Date的classpath?

原因在于,就像java的Path路徑已經(jīng)悄悄在后臺(tái)設(shè)置好一樣,rt.jar的classpath路徑也悄悄地在后臺(tái)設(shè)置了。因此,我們不必多此一舉手工設(shè)置其classpath了。

23.?最后一點(diǎn)需要談到的是,如果主類(lèi)恰好也在一個(gè)package中(在大型的開(kāi)發(fā)中,其實(shí)這才是一種最常見(jiàn)的現(xiàn)象),那么java命令行的類(lèi)名前面就必須加上包名。

在C:\Java?Test下面新建一個(gè)文件夾,名為NF。將C:\Java?Test下面的Hello.class刪除,將Hello.java移到NF文件夾下。打開(kāi)NF文件夾下的Hello.java,為其設(shè)置package屬性。

package?NF;

import?DF.Person;
import?java.util.Date;

public?class?Hello?{
??public?static?void?main(String[]?args)?{
????Date?date?=?new?Date();
????System.out.println(date);

????Person?person?=?new?Person("Mike");
????System.out.println(person.getName());
??}
}

編譯與以前沒(méi)啥區(qū)別,只不過(guò)是修正一下改過(guò)之后的路徑。

javac?-classpath?"C:\Java?Test"?"C:\Java?Test\NF\Hello.java"

而java命令行卻有了變化

java?-classpath?"C:\Java?Test"?NF.Hello

上面命令行語(yǔ)句中,NF.Hello告訴JDK,Hello.class在NF的package下面。

至此,本文有關(guān)classpath及package的問(wèn)題的討論已經(jīng)全部結(jié)束。由此可見(jiàn),Java的入門(mén)的確非常不易。如果初學(xué)Java的程序員一見(jiàn)到Java的編譯竟是如此的復(fù)雜,多半就會(huì)抽身而退。因此,筆者認(rèn)為,Sun在J2SE的Tutorial中故意將編譯的問(wèn)題盡量簡(jiǎn)單化,以吸引更多的Java初學(xué)者。一旦品嘗了Java的香醇可口的美味后,就不用擔(dān)心他們退出了,因?yàn)榭Х仁欠浅H菀鬃屓松习a的。

From:http://www.programbbs.com/doc/show.asp?ID=437