包的內容
包的內容應該仔細設計,使其只包含在功能上相關的類和介面。包中的類可以自由地訪問該包中其他類的非私人成員,有些類甚至可能有足夠的許可權去訪問其他類的內部細節,為了避免這樣的類對類成員進行誤操作,我們需要對類成員進行保護。任何沒有被聲明為private的成員都可以被同一個包中的其他所有類型訪問,所以任何不相關的類之間的藕合程度都可能會比我們所期望的程度高。
包還為尋找有用的介面和類的程式員提供了邏輯分組的功能。由不相關的類組成的包使程式員很難分辨出哪些介面和類是有用的,而類的邏輯分組可以協助程式員重用代碼,因為程式員通過邏輯分組能夠更容易地找到他們所需要的東西。如果包中只包含相關的、緊藕合的類型集,則意味著我們可以給類型取一些更直觀的名字,從而避免名字衝突。
包可以嵌套。例如,java.lang就是一個嵌套包,其中,包Lang嵌套在更大的包java中,而包j ava卻還包含一些其他的包。嵌套使得相關的包構成了具有階層的命名系統。
例如,為了建立一組包,用於諸如神經網路和遺傳演算法這樣的自適應系統,我們可以用以圓點分隔的名字來命名包,從而建立嵌套包:
package adaptive. neural Net;
含有上面這條聲明語句的源檔案位於adaptive.neuralNet包中,而adaptive.neuralNet包本身又是adaptive包的子包。adaptive包中可能包含一些與通用的自適應演算法相關的類,例如泛化問題陳述類或基準測試類別。在階層中處於更深位置的包(例如adaptive. neu-ralNet或adaptive.genetic)包含與特定類型的自適應演算法相關的類。
包的嵌套僅僅是組織相關包的一種工具,它並不能提供包之間的任何特殊的存取權限。
adaptive.genetic包中的類代碼無法訪問adaptive或adaptive.neuralNet包中具有包存取權限的成員,包範圍只適用於特定的包。包的嵌套可以對相關的包進行分組,並協助程式員更方便地在邏輯層次中找到想要的類,但是除此之外,它並未帶來其他的任何益處。
包的註解
包也可以有註解。但是問題在於,由於包是一種組織圖,沒有原始碼實體,它們並沒有實際的定義,所以不能像對類或方法那樣對它們進行註解,因此包的註解只能通過在源檔案中對包的聲明語句進行註解來實現。然而,在每個包中只能有一個包聲明可以擁有作用於它的註解。
那麼究竟如何對包進行註解呢?事實上,Java語言並沒有強製程序員必須使用某種方式來處理“單一註解的包語句”規則。所建議的方式是在包目錄中建立一個名為package一i nfo.java的檔案,在這個檔案中只儲存包語句和該包的註解,而不放置任何其他內容。例如,用於attr包的package一info.java檔案看起來就是這樣的:
@PackageSpec(name二”Attr Project",version="1.0" @DevelopmentSite("attr.project.org") @DevelopmentModel("open一source") package attr;
其中Packagespec,Developmentsite和Devel opmentmodel用來修飾註解類型,當然,它們具有運行時的儲存策略。package一info.java檔案應該和包中的其他源檔案一起編譯。
我們推薦將所有與包相關的資訊都放置在package一info. java檔案中。如果你這樣做了,那麼你就可以在檔案的開頭放置文檔注釋,從而使這些文檔被注釋成包文檔。
包對象和規範
包通常會實現某種規範,並且通常是來自於某個組織的。Package對象與其他的反射類型不同,不能用來建立或操作包,而只能充當提供資訊的知識庫,用來提供有關包所實現的規範的資訊(規範的標題、供應商和版本號碼)和有關包的實現本身的資訊(包的標題、供應商和版本號碼)。雖然包通常來自於單個的組織,但它所實現的規範(如統計分析庫)卻可能是其他組織已定義過的。使用包的程式可能需要知道該包所實現的規範的版本,從而可以使用只在某個版本中定義的功能。類似地,這些程式還可能需要知道提供給它的是哪個實現版本,這主要是為了處理在不同版本中可能存在的缺陷。Package類的一些主要方法允許訪問到這些資訊:
- ·public Stri ng getName ():返回該包的名字。
- .public string getspecificationTitle p:返回該包所實現的規範的標題,如果標題未知,則返回null,
- .public string getspecificationversion():返回一個描述該包所實現的規範的版本資訊的字串,如果版本資訊未知,則返回null,
- .public string getspecificationvendor Q:返回供應商的名字,這個供應商擁有並維護該包所實現的規範,如果供應商未知,則返回null,
- .public string getImplerentationTitle():返回該包所提供的實現的標題,如果標題未知,則返回null, ·public string getImplementationversion():返回一個描述該包所提供的實現的版本資訊的字串,如果版本資訊未知,則返回null,
- ·public string getImplementationvendor():返回提供該實現的組織(供應商)的名字,如果該組織未知,則返回null,
例如,在我們的系統中提取java.lang包的這些資訊,將會得到如下結果:'
Specification Title: Java Platform API Specification Specification Version: 1.4 Specification Vendor:Sun Microsystems,Inc. Implementation Title:Java Runtime Environment Implementation Version:1.5.0_02 Implementation Vendor: Sun Microsystems,Inc.
規範版本號碼由句點分隔字元分開的非負數字組成,如‘'2.0'‘或”11.0.12"。這種模式使得我們可以調用iscompatiblewith方法對遵循該模式的版本號碼與包的版本號碼進行比較。如果包的版本號碼大於等於傳人的版本號碼,那麼該方法就返回true。這種比較每次只比較一個由句點分隔的數字,如果這些數字中任何一個小於傳遞進來的版本號碼中對應位置的值,那麼這兩個版本就不相容。如果其中一個版本號碼比另一個長,那麼在短的版本號碼中缺少的部分將被認為是零。例如,如果包的規範版本號碼是”1.4",並且我們用iscompatiblewith方法將其與”1.2","1.3.1'.或”.1.81.進行比較時,那麼將返回true;但是如果與''1.4.2'.或”.5"進行比較,那麼將返回false。之所以得出這樣的結論,是因為這種比較機制假設規範版本是向後相容的。
實現的版本號碼沒有規定的格式,因為提供實現的不同組織會對實現版本做不同的定義。在實現版本之間唯一能做的比較是測試版本是否相同,其中沒有向下相容的假設。
包可以被密封起來,這意味著不能再向這個包中添加類了。未密封的包可以包含來自類搜尋路徑中多個不同位置的類,而被密封的包的內容必須來自相同的位置—要麼是某個特定的歸檔檔案,要麼是由某個URL指定的位置。有兩種方法可以確定一個包是否被密封了:
.public boolean issealed p:如果該包被密封了,則返回trueo
.public boolean issealed(URL url):如果該包對於給定的URL是密封的,則返回true,也就是說,該包中的類可以從這個給定的URL處載入。如果包中的類不能從給定的URL載入,或者包沒有被密封,則返回false,包的規範和實現資訊通常是作為與包儲存在一起的資訊清單檔的一部分而提供的—例如作為Java歸檔檔案(jar)中的資訊清單檔的一部分,就像25.9.2節“歸檔檔案java.util.jar”中描述的那樣。當載入包中類時,這些資訊就會被讀人。類載入器(ClassLoader)可以為它要載入的類動態地定義一個Package對象:
我們可以調用給定類的Class對象的getPackage方法來獲得這個類的Package對象。我們也可以用給定的包名調用靜態方Package.getPackage來獲得Package對象,或者調用靜態方Package.getPackages,它將返回由類載入器當前已知的所有包組成Package數組。這兩個方法都與調用它們的代碼的類載入器有關,因為這些代碼將調用其類載入器的get-Package或getPackages方法。這些類載入器的方法將搜尋特定的類載入器及其所有父類載入器,如果對當前類載入器沒有做任何設定,那麼此時就會使用系統類別載入器。請注意,如果包未知,那麼類載入器方法將返回null,因為此時還沒有載入包中的任何類型。