標籤:java許可權 存取權限 public private protected
第六章 存取權限控制簡介
Java提供了存取權限修飾詞,供類庫開發人員向用戶端程式員指明哪些是可用的,哪些是停用。存取權限控制的等級,從最大許可權到最小許可權一次為:public、protected、包(library)存取權限(沒有關鍵詞)以及private。
6.1 包(library):庫單元
包內含有一組類,它們在單一的名字控制項之下被組織在一起。例如,在Java的標準發布中有一個工具庫,它被組織在java.util名字空間之下。java。util中有一個叫ArrayList的類,使用ArrayList的一種方式是用其全名java.util.ArrayList來指定。例如:
public class Test { public static void main(String[] args) { java.util.ArrayList list = new java.util.ArrayList(); }}
有沒有覺得很長很麻煩,可以用import關鍵字來匯入該類,例如:
import java.util.ArrayListpublic class Test { public static void main(String[] args) { ArrayList list = new ArrayList(); }}
我們需要通過匯入來給類一個名字空間。如果同時有兩個名字為Stack類並且在同一機器上面了,這時候需要對名稱空間進行完全控制,給每個類貼上唯一的標籤。
當編寫一個Java原始碼檔案的時候,此檔案通常被成為編譯單元,每個編譯單元都必須由一個尾碼名.java,在編譯單元的內部可以有一個由關鍵詞public修飾的類,該類的名稱必須和檔案名稱相同,否則編譯器報錯。如果在編譯單元裡面有額外的類,這些類不是public的,在包之外無法被看見。
6.1.1 程式碼群組織
當編譯一個.java檔案時,在檔案中的每個類都會有一個輸出檔案,輸出的檔案名稱和類名稱相同,尾碼名為.class。因此在編譯少量.java檔案之後,可能會的到很多.class檔案,如果用編譯性語言(例如C),編譯之後產生的中間檔案(通常是一個obj檔案),然後再通過連結器(用來建立一個可執行檔)或類庫產生器(librarian,用來建立一個類庫)產生的其他同類檔案綁定一起。
但這不是Java的工作方式,Java可運行程式是一組可以打包並且壓縮為一個Java文檔檔案(JAR,使用Java的jar文檔產生器)的.class檔案。Java解譯器負責這些檔案的尋找、裝載和解釋。
類庫實際上是一組類檔案。其中每個檔案都有一個public類,以及人以數量的非public類。如果希望.java檔案從屬於同一個群組,就可以用到package關鍵字。
package語句必須是一個編譯單元中(.java檔案)除了注釋之外的第一行程式碼。例如package access;。就表明該類是名為access的類庫的一部分。例如
package access.mypackage;public class MyClass { .....}
定義好了類MyClass並且為其指定好了包名之後,如果需要用到該類,就需要用關鍵字import來匯入類。
import access.mypackage.*;public class Test { public static void main(String[] args) { MyClass class = new MyClass(); }}
6.1.2 建立獨一無二的包名
為了避免多個包的檔案在同一個目錄下混雜,一中合乎邏輯的做法就是將特定的包的所有.class檔案都放置於一個目錄下。利用作業系統的層次化的檔案結構來解決這一問題。
將所有的檔案收入一個子目錄還可以解決另外的兩個問題:
- 按照慣例,package名稱的第一部分是類的建立者的反順序Internet網域名稱,如果按照管理來命名,package的名稱也將是獨一無二的,防止了名稱衝突的問題。
- 將package名稱分解成本機上的一個目錄。當Java程式運行並載入需要的.class檔案時,就可以很直觀的確定出檔案所在的目錄。
Java解譯器的運行過程如下:找出環境變數CLASSPATH(可以通過作業系統來設定),CLASSPATH包含了一個或者多個目錄,用作尋找.class檔案的根目錄。從根目錄開始,解譯器擷取包的名稱並將每個句點替換成反斜線,以從CLASSPATH根中產生一個路徑名稱(例如包名foo.bar.baz就會變成foo\bar\baz或者foo/bar/baz,取決於作業系統)。得到的路徑會和CLASSPATH中相對應的目錄結合,解譯器就在這些目錄中尋找和需要建立的類名相同的.class檔案了。
6.1.3 對使用包的告示
無論何時建立包,都已經在給定包名稱的時候隱含的指定了目錄結構。這個包必須位於其命名所指定的目錄之中,而該目錄必須是在CLASSPATH開始的目錄中可以查詢到的。注意,編譯過的代碼通常放置在和原始碼不同的目錄中,但必須保證JVN使用CLASSPATH能找到該路徑。
6.2 Java存取權限關鍵詞
public、protected、private這幾個Java存取權限修飾詞在使用的時候,是放在類中每個成員的定義之前,無論這個成員是一個方法還是變數。如果不提供任何形式存取權限修飾,則意味著它是”包(package)存取權限”。
6.2.1 包(package)存取權限
類中的預設存取權限沒有任何的關鍵字,但通常指的是包存取權限(有時也表示稱friendly)。這就意味著當前包中的所有其他類對該成員都有訪問的許可權,但對這個包之外的所有類,卻表現出private的特性。
包存取權限允許將包內所有相關的類組合起來,以使它們可以輕鬆的相互作用。當把類組織起來放進一個包內時,也就給他們的報存取權限的成員賦予了相互訪問的許可權。
6.2.2 public:介面存取權限
使用關鍵字public,也就意味著後面緊跟著的成員無論對誰都可直接存取,假設定義了一個包含下面編譯單元的dessert包:
package access.dessert;public class Cookie { public Cookie() { System.out.println("Cookie constructor"); } void bite() { System.out.println("bite"); }}
現在如果建立了一個使用Cookie類的程式:
import access.dessert.*;public class Dinner { public static void main(String[] args) { Cookie x = new Cookie(); }}
這樣就可以建立一個Cookie對象了,但是由於bite方法是包內存取權限,不在一個包內,故無法訪問該方法。
預設包:如果對兩個類都沒有用package關鍵字指明所處的包,則會預設該檔案你屬於該目錄的預設包中,如果這兩個類在同一個子目錄下,則是可以互相訪問包存取權限的成員的。如果上面的例子中兩個類檔案處於同一目錄下,則可以調用x.bite()方法,否則會報錯。
6.2.3 private:無法訪問
關鍵字private的意思是,除了包含該成員的類之外,其他任何類都無法訪問這個成員。下面的例子使用了private關鍵字:
class Sundae{ private Sudae() { static Sudae makeASudae(){ return new Sudae(); }}public class IceCream { public static void main(String[] args) { Sundae x = Sundae.makeSundae(); }}
這個例子阻止外界直接接觸構造器,而用作者提供的構造器來建立類的執行個體。
任何可以肯定只是該類的一個”助手”的方法,都可以指定成private,以確保不會再包內其他地方誤用。
6.2.4 protected:繼承存取權限
關鍵字protected處理的是繼承的概念,通過繼承可以利用一個基類,然後將新成員添加到現有類中而不用碰該現有類。還可以改變該類現有成員的行為。
如果建立了一個新包,並繼承來自另外一個包的基類,則唯一能訪問的成員就是基類中的public成員。基類的建立者會希望某個特定的成員,把它的存取權限賦予它的子類而不是所有類,這就需要用到protected關鍵字。protected也提供包存取權限,也就是說是加強版的預設存取權限,除了同一包裡的類可以訪問之外,還允許繼承它的類訪問。下面的例子:
//Cookie.javapackage access.dessert;public class Cookie { public Cookie() { System.out.println("Cookie constructor"); } void bite() { System.out.println("bite"); }}
目前對方法bite()有存取權限的只有同一包下的。
如果再建立一個類繼承Cookie,並將bite()方法的存取權限改為protected
。
//SmallCookie.javapackage dada.lifepublic class SmallCookie extends Cookie{ public SmallCookie() { System.out.println("SmallCookie constructor"): } public void smallBite() { bite(); } public static void main() { SmallCookie sc = new SmallCookie(); sc.smallBite(); }}
這時候SmallCookie對Cookie中的bite()方法就具有了存取權限。
6.4 類的存取權限
Java中,存取權限修飾詞也可以用於確定庫中的哪些類對於使用者時可用的。
為了控制某個類的存取權限,修飾詞必須出現在關鍵字class之前。例如public class Widget{},然而在使用關鍵字限制存取權限的時候還有些注意事項:
- 每個編譯單元(檔案)都只能有一個public類。每個編譯單元都有單一的公用介面,用public來修飾。
- 被public修飾的類必須和編譯單元(檔案)同名,包括大小寫。
請注意,類的存取權限既不可以是private(這樣會使其他的任何類都無法訪問它)也不能是protected的。所以對類的存取權限只有兩個選擇:包存取權限或者public。如果不希望其他任何人對該類擁有存取權限,可以把所有構造器都設定為private。
如果沒能為類存取權限指定一個存取修飾詞,它就會預設的得到包存取權限。這就意味著該類的對象可以由包內的任何其他類來建立,但是在包外則不行。(在類的最開頭,由package指定的包名相同則視為同一包下,還需要注意預設包名~)。
Thinking In Java筆記(第六章 存取權限控制)