Java編程思想:第六章:訪問控制

第六章:訪問控制


    訪問控制(或者隱藏具體實現)與(最初的實現並不恰當)有關。

    所有的優秀作者,包括哪些編寫軟件的程序員,都清楚著作的某些部分直至重新創作的時候才變得完美,有時甚至要反覆重寫幾次。如果你把一個代碼段放到了某個位置,等過一會回頭再看時,有可能會發現優更好的方式去實現相同的功能。這正是重構的原則之一。重構及重寫代碼,以使得它更好的可讀,更易理解, 並因此而更具可維護性。

    但是,這種修改和完善代碼的願望之下,也存在着巨大的壓力。通常總是會有一些消費者(客戶端)需要你的代碼在某些方面保持不變。因此,你想改變代碼,而他們卻像讓代碼保持不變,因此而產生了在面向對象編程中需要考慮的一個基本問題:“如何把變動的事務與保持不變的事務區分開來”。

    這對類庫而言尤爲重要。該類的消費者必須依賴他所使用的那部分類庫,並且能夠知道如何類庫出現了新的版本,他們並不需要改寫代碼。從另一個方面來說,類庫的開發者必須要有權限進行修改和改進,並確保客戶代碼不會因爲這些改動而受到影響。

    這一目標可以通過約束來達到,爲了解決這個問題Java提供了訪問修飾符,以供類庫開發人員向客戶端程序員指明那些是可用的,那些是不可用的。

    訪問權限控制的等級,從最大權限到最小權限依次爲:

    • public

    • protected

    • private

    不過構建類庫的概念以及對於誰有權取用該類庫的構建的控制問題還是不完善的。其中仍舊存在着如何將構建捆綁到一個內聚的類庫單元中的問題。對於這一點,Java用關鍵字package加以控制,而訪問權限修飾詞會因類是存在於一個相同的包,還是存在於一個單獨的包而受到影響。


6.1 包:庫單元

    包內包含有一組類,它們在單一的名字空間之下被組織在一起。導入一般使用:import java.util.*;

    我們之所以導入包,就是要提供一個管理名字空間的機制。所有類成員的名稱都是彼此隔離的。由於名字之間的衝突,Java對名稱空間進行了完全控制併爲每個類創建唯一的標識符組合就稱爲了非常重要的事情。

    當編寫一個Java源代碼文件時,此文件通常被稱爲編譯單元。每一個編譯單元必須有一個後綴爲.java,而在編譯單元內則可以有一個public類,該類的名稱必須與文件的名字相同。每一個編譯單元只能有一個public類,否則編譯器就不會接受。如果編譯單元中有額外的類的話,那麼在包之外的世界是無法看到這些類的,就是因爲他們不是public的,而且它們主要用來爲主poblic類提供支持。


代碼組織

    當編譯一個.java文件時,文件中的每一個類都會有一個輸出文件,而且該輸出文件的名字與.java文件中的每一個類的名稱相同。只是多了一個後綴名.class。因此,在編譯少量.java文件之後,會得到大量的.class文件。Java可運行程序是一組可以打包並解壓爲一個java文檔文件的.class文件。Java解析器負責這些文件的查找,裝載,解析。

    類庫實際上是一組類文件。其中每一個文件都有一個public類,以及任意數量的非public類。因此,每個文件都有一個構建。如果希望這些構建從屬於同一個羣組,就可以使用關鍵字package。

    如果使用package關鍵字,它必須是文件中去除註釋外的第一句程序代碼。在文件起始處寫。如下:package.utils; 表示該編譯單元是名稱未utils的類庫的一部分。或者換種說話,你正在聲明該編譯單元中的public類名稱是位於utils名稱的保護傘下。任何想要使用該名稱的人都必須使用前面給出的選擇,指定全名或者與utils結合使用import。

    身爲一個類庫設計員,要記住,package和import關鍵字允許你做的,是將單一的全局名字空間分隔開,使得無論多少人使用Internet以及Java開會編寫類,都不會出現名稱衝突問題。


創建獨一無二的包名

    特定包的所有.class文件都置於一個目錄下。也就是,操作系統的層次化的文件系統結構來解決這個問題。這是Java解決混亂問題的解決方式。

    將所有的文件收入一個子目錄還可以解決另外兩個問題:

    • 怎樣創建獨一無二的名稱以及怎樣查找有可能隱藏於目錄結構中的某些類。一般package就是倒過來的域名,是獨一無二的。因此你的package名稱也是獨一無二的。所以不會出現衝突問題。

    • 此技巧的第二部分是,把package名稱分解爲你機子上的一個目錄。

    Java解析器的運行過程如下:

    • 首先,找出環境變量CLASSPATH。CLASSPATH包含一個或多麼目錄,用作查找.class文件的根目錄。從根目錄開始,解析器獲得包的名稱並將每一個句點替換成反斜槓,已從CLASSPATH根中產生一個路徑名稱,得到的路徑會與CLASSPaTH中各個不同的項相連接,解析器就在這個目錄中查找與你所要創建的類名稱相符的.class文件。

    使用import引入時注意衝突哦。


用import改變行爲

    Java中沒有條件編譯,一般調試時可以用到次動能。比如:創建兩個包dev,test。然後用import來切換。


對使用包的忠告

    務必記住,無論何時創建包,都已經在給定包的名稱的時候隱含指定了目錄結構。這個包必須位於名稱所指定的目錄中,而該目錄必須在以CALASPATH開始的目錄中可以查詢到的。最初使用關鍵字package,可能會有一點不順,因爲除非遵守“包的名字對應目錄路名”的規則,否則將會許多出乎意料的運行時信息。


6.2 Java的訪問修飾符

image.png


6.3 接口與實現

    訪問權限的控制常被稱爲具體實現的隱藏。把數據和方法包裝進類中,以及具體實現的隱藏,常共同被稱爲封裝。其結果是一個同時帶有特徵和行爲的數據類型。

    出於兩個很重要的原因,訪問權限控制將權限的邊界劃在了數據類型的部分,如下:

    • 要指定客戶端程序員可以使用和不可以使用的邊界。可以在結構中建立自己的內部機制,而不必擔心客戶端程序員會偶然地將內部機制當做是他們可以使用的接口的一部分。

    • 將接口和具體實現分離。

    爲了清晰起見,可能會採用一種將public成員置於開頭,後面跟着protected,包訪問權限和private成員的創建類的形式。這樣做的好處是使用者可以從頭讀起,首選閱讀對他而言最重要的部分,等到遇見作爲內部實現細節的非public成員時停止閱讀。


6.4 類的訪問權限

    在Java中,訪問權限修飾符也可以用於確定庫中的哪些類對於該庫的使用者是可用的。如果希望某個類可以爲某個客戶端程序員所用,就可以通過public關鍵字作用於整個類的定義來達到目的。這樣做甚至可以控制客戶端程序員是否能創建一個該類的對象。

    這裏有一些額外的限制:如下:

    • 每個編譯單元都只能有一個public類。這表示,每個編譯單元都有單一的公共接口,用public類來表示。該接口可以按要求包含衆多的支持包訪問權限的類。如果再某個編譯單元內有一個以上的public類,編譯器就給出錯信息。

    • public類的名稱必須完全與含有編譯單元的文件名相匹配,包括大小寫。

    • 雖然不是很常見,但編譯單元內完全不帶public類也是可能的。在這種情況下,可以隨意對文件命名。

    比如,內部類,去掉public就包權限了,而且客戶端程序員也不會放到問,隱藏了細節。

    類是不可以設置成private的,所以類而言只有兩種選擇:

    • 包權限

    • public

    如果不希望別人對類訪問權限,可以把構造器改成private來防止new出對象。但是有一個例外,就是你在該類的static成員內部可以創建。

    正如前面所提到的,如果沒能爲類訪問權限指定一個訪問修飾符,它就會默認得到包訪問權限。這意味着該類的對象可以由包內任何其他類來創建。但在包外則是不行的。然而,如果該類的某個static成員是public的,則客戶端程序員仍舊可以調用該static成員。儘管他們並不能生成該類的對象。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章