當前位置:編程學習大全網 - 源碼下載 - 如何理解和使用Java package包

如何理解和使用Java package包

Java中的壹個包就是壹個類庫單元,包內包含有壹組類,它們在單壹的名稱空間之下被組織在了壹起。這個名稱空間就是包名。可以使用import關鍵字來導入壹個包。例如使用import java.util.*就可以導入名稱空間java.util包裏面的所有類。所謂導入這個包裏面的所有類,就是在import聲明這個包名以後,在接下來的程序中可以直接使用該包中的類。例如:

[java] view plain copy

import java.util.*

public class SingleImport

{

public static void main(Strin[] args)

{

ArrayList list=nwe ArrayList();

}

}

這裏ArrayList就是java.util包中的壹個類,但是由於對程序使用了import關鍵字加載了java.util包,所以這裏並沒有見到對ArrayList類的定義和聲明,也沒有見到該類前面有什麽限定名,就可以直接使用這個類。

我們之所以要導入包名,就是要提供壹個管理名稱空間的機制。我們知道,如果有兩個類A類和B類都含有壹個具有相同特征標記(參數列表)的方法f(),即便在同壹段代碼中同時使用這兩個方法f(),也不會發生沖突,原因就在於有兩個不同的類名罩在前面作為限定名,所以兩個方法即便同名也不回發生沖突。但是如果類名稱相互沖突又該怎麽辦呢?假設妳編寫了壹個Apple類並安裝到了壹臺機器上,而該機器上已經有壹個其他人編寫的Apple類,我們該如何解決呢?因為妳如果想弄清楚壹臺機器上到底已經安裝了那些類,並不是壹件很容易的事情,所以名字之間總是有存在潛在的沖突的可能。在Java中對名稱空間進行完全控制並為每個類創建唯壹的標識符組合就成為了非常重要的事情。如果妳要編寫對於同壹臺機器上***存的其他Java程序友好的類庫或程序的話,就需要考慮如何防止類名稱之間的沖突問題。

當編寫壹個Java源代碼文件時,此文件通常被稱為編譯單元。每個編譯單元都必須有壹個後綴名.java,而在編譯單元內有且僅有壹個public類,否則編譯器就不會接受。該public類的名稱必須與文件的名稱相同(包括大小寫,但不包括後綴名.java)。如果在該編譯單元之中還有額外的類的話,那麽在包之外的世界是無法看見這些類的,因為它們不是public類,而且它們主要用來為主public類提供支持。

當編譯壹個.java文件(即壹個編譯單元)時,在.java文件中的每個類都會有壹個輸出文件,而該輸出文件的名稱與.java文件中每個類的名稱相同,只是多了壹個後綴名.class。因此在編譯少量.java文件之後,會得到大量的.class文件。每壹個.java文件編譯以後都會有壹個public類,以及任意數量的非public類。因此每個.java文件都是壹個構件,如果希望許許多多的這樣的構件從屬於同壹個群組,就可以在每壹個.java文件中使用關鍵字package。而這個群組就是壹個類庫。

如果使用package語句,它必須是.java文件中除註釋以外的第壹句程序代碼。如果在文件的起始處寫:

package fruit;

就表示妳在聲明該編譯單元是名為fruit的類庫的壹部分,或者換句話說,妳正在聲明該編譯單元中的public類名稱是位於fruit名稱的保護傘下,由fruit名稱罩著。任何想要使用該public類名稱的人都必須指定全名或者與fruit結合使用關鍵字import。

例如,假設文件的名稱是Apple.java,這就意味著在該文件中有且僅有壹個public類,該類的名稱必須是Apple(註意大小寫):

[java] view plain copy

package fruit;

public class Apple

{

//...

}

上面的代碼已經將Apple類包含在了fruit包中,現在如果有人想使用Apple或者是fruit中的任何其他public類,就必須使用關鍵字import來使fruit中的名稱可用。

[java] view plain copy

import fruit.*;

public class ImportApple

{

public static void main(String[] args)

{

Apple a=new Apple();

}

}

或者使用完整限定名稱:

[java] view plain copy

public class QualifiedApple

{

public static void main(String[] args)

{

fruit.Apple a=new fruit.Apple();

}

}

顯然使用關鍵字import使代碼更加簡潔。

作為壹名程序員,我們應該牢記:package和import關鍵字允許做的是將單壹的全局名稱空間分割成各自獨立封閉的名稱空間,使得無論多少人使用Internet以及Java開始編寫類,都不會出現與我們的類名稱相沖突的問題,因為我們的類是被封閉在我們自己定義的獨立的名稱空間裏面的,而非在公***的全局名稱空間裏面。

到這裏也許妳會發現,其實所謂關鍵字package打包從未將被打包的東西包裝成壹個單壹的文件,並且壹個包可以由許多.class文件構成,這就存在將兩個名稱相同的類打進壹個包中的可能。為了避免這種情況的發生,壹種合乎邏輯的做法就是將特定的所有.class文件都置於壹個目錄下。也就是說利用操作系統的層次化的文件結構來解決這壹問題。這是Java解決混亂問題的壹種方式(這裏暫且先不討論JAR包工具)。

將所有的文件收入壹個子目錄還可以解決另外兩個問題:壹、怎樣創建獨壹無二的名稱;二、怎樣查找有可能隱藏於目錄結構中某處的類。

這些任務是通過將.class文件所在的路徑位置編碼稱package的名稱來實現的。

按照慣例,package名稱的第壹部分是類的創建者的反順序的Internet域名。為什麽要用Internet域名呢?因為如果妳遵照慣例,Internet域名應該是獨壹無二的,因此妳的package名稱也將是獨壹無二的,也就是前面提到的我們自定義的獨立封閉的名稱空間將是獨壹無二的,這樣就不會出現名稱沖突的問題了。當然,如果妳沒有自己的域名,妳就得構造壹組不大可能與他人重復的組合(例如妳的姓名),來創立獨壹無二的package名稱。如果妳打算發布妳的Java程序代碼,稍微花費些代價去取得壹個域名還是很有必要的。

另外,如果妳的Java程序代碼只是在本地計算機上運行,妳還可以把package名稱分解為妳機器上的壹個目錄。所以當Java程序運行並且需要加載.class文件的時候,它就可以根據package名稱確定.class文件在目錄上的所處位置。

程序在運行的時候具體是如何確定.class文件位置的呢?

來看看Java解釋器的運行過程吧:首先,找出環境變量CLASSPATH(可以通過操作系統來設置)。CLASSPATH包含壹個或多個目錄,用作查找.class文件的根目錄。從根目錄開始,解釋器獲取包名稱並將每個句點替換成反斜杠,以從CLASSPATH根中產生壹個路徑(例如,package fruit.Apple就變成為fruit/Apple或fruit/Apple或其他,這將取決於操作系統)。得到的路徑會與CLASSPATH中的各個不同的根目錄路徑相連接以獲得壹個完整的目錄路徑,解釋器就在這些目錄中查找與妳所需要的類名稱相同的.class文件。(此外,解釋器還會去查找某些涉及Java解釋器所在位置的標準目錄。)

為了理解這壹點,以域名Food.net為例。把它的順序倒過來,並且全部轉換為小寫,net.food就成了我們創建類的壹個獨壹無二的名稱空間。如果我們決定再創建壹個名為fruit的類庫,我們可以將該名稱進壹步細分,於是得到壹個包名如下:

package net.food.fruit;

現在,這個包名稱就可以用作下面Apple這個文件的名稱空間保護傘了:

[java] view plain copy

package net.food.fruit;

public class Apple

{

public Apple()

{

System.out.println("net.food.fruit.Apple");

}

}

這個文件可能被置於計算機系統中的如下目錄中:

C:/DOC/JavaT/net/food/fruit

之所以要放在這個目錄下面是因為前面提到的,便於系統通過CLASSPATH環境變量來找到這個文件。沿著此路徑往回看就能看到包名net.food.fruit,但是路徑的前半部分怎麽辦呢?交給環境變量CLASSPATH吧,我們可以在計算機中將環境變量CLASSPATH設置如下:

CHASSPATH=.;D:/JAVA/LIB;C:/DOC/JavaT

CLASSPATH可以包含多個可供選擇的查詢路徑。每個路徑都用分號隔開,可以看到,上面這個CLASSPATH環境值的第三個路徑就是我們前面文件的根目錄。如前所述,Java解釋器將首先找到這個根目錄C:/DOC/JavaT,然後將其與包名net.food.fruit相連接,連接的時候將包名中的句點轉換成斜杠,就得到完整的class文件路徑C:/DOC/JavaT/net/food/fruit。

需要補充說明的壹點,這裏CLASSPATH環境變量關照的是package中的class文件,如果關照的是JAR包中的class文件,則會有壹點變化,即,必須在CLASSPATH環境變量路徑中將JAR文件的實際名稱寫清楚,而不僅僅是指明JAR包所在位置目錄。可以想象,因為JAR包所在目錄位置上可能存在很多別的JAR包,而我們需要使用的那個class文件只會存在於其中壹個JAR包裏面,因此可以這樣理解,這裏JAR包實際上也充當了壹級文件目錄的角色,因此要在CLASSPATH環境變量中寫清楚JAR包文件名。例如如果Apple文件存在於名為fruit.jar的JAR文件中,則CLASSPATH應寫作:

CLASSPATH=.;D:/JAVA/LIB;C:/DOC/JavaT/net/food/fruit.jar

壹旦路徑得以正確建立,下面的文件就可以放於任何目錄之下:

[java] view plain copy

import net.food.fruit.*;

public class LibTest

{

public static void main(String[] args)

{

Apple a=new Apple();

}

}

當編譯器碰到fruit庫的import語句時,就開始在CLASSPATH所指定的目錄中查找,查找過程中分別將CLASSPATH中設定的各項根目錄與包名轉換來的子目錄net/food/fruit相連接,在連接後的完整目錄中查找已編譯的文件(即class文件)找出名稱相符者(對Apple而言就是Apple.class)。找到了這個文件即匹配到了Apple類。

  • 上一篇:繪本界的奧斯卡,凱迪克大獎47部,搞定孩子整個寒假閱讀(上)
  • 下一篇:有哪位知道洪晃blog中提到的《生銹的鉆石》那首歌英文名叫什麽?謝謝!
  • copyright 2024編程學習大全網