跳至主要内容

6.2 Java 訪問權限修飾詞解析及其應用

訪問權限控制與封裝

  • 訪問權限的控制常被稱為具體實作的隱藏,將數據和方法包裝到類別中,以及隱藏具體實作,通常被統稱為封裝
  • 訪問權限控制將權限的邊界設定在數據類型的內部
    • 設定客戶端程式員可使用與不可使用的界線,避免客戶端意外將內部機制當作可使用的介面
    • 將介面與具體的實作進行分離,客戶端除了向介面發送訊息之外什麼也不可以做,這樣可以隨意更改非 public 的部分而不會破壞客戶端程式碼
  • 通常為了清晰起見,會採用 public ⇒ protected ⇒ package access ⇒ private 的順序來定義 class,好處是使用者可以從頭讀起並且首先閱讀對他們來說最重要的部分 (由於 public 可以被外部調用),遇到非 public 成員時便可以停止閱讀
public class OrganizedByAccess {
public void pub1() { /* ... */ }
public void pub2() { /* ... */ }
public void pub3() { /* ... */ }
private void priv1() { /* ... */ }
private void priv2() { /* ... */ }
private void priv3() { /* ... */ }
private int i;
// ...

類別的訪問權限設置 (class access)

  • 在 Java 中,訪問權限修飾詞也可以用來確定 library 中哪些 class 對該 library 的使用者來說是可用的
  • 為了控制某個 class 的訪問權限,修飾詞要出現在關鍵字 class 之前
package access;

public class Widget {}
  • 客戶端可以透過下面的宣告訪問 Widget
import access.Widget;
// 或
import access.*;
  1. 每個編譯單元 (檔案) 都只能有一個 public 類別,否則編譯器會報錯
  2. public 類別的名稱必須完全與含有該編譯單元的檔案名稱匹配,包含大小寫
    1. 因此對於 Widget,檔案名稱必須是 Widget.java
    2. WIDGET.javawidget.java 編譯器都會報錯
  3. 編譯單元完全不帶 public 類別也是可以的,這情況下可以隨意命名檔案
  • 類別不能是 privateprotected,對於 class 來說,只有 package access 或 public 兩種選擇 (內部類別為例外)
    • 如果不希望任何人對該 class 有訪問權限,可以把 constructor 都指定為 private
    • 有一個例外是可以利用該 class 的 static 內部成員創建
class Soup1 {
private Soup1() {}
// (1) Allow creation via static method:
public static Soup1 makeSoup() {
return new Soup1();
}
}

class Soup2 {
private Soup2() {}
// (2) Create a static object and return a reference
// upon request.(The "Singleton" pattern):
private static Soup2 ps1 = new Soup2();
public static Soup2 access() {
return ps1;
}
public void f() {}
}

// Only one public class allowed per file:
public class Lunch {
void testPrivate() {
// Can't do this! Private constructor:
//! Soup1 soup = new Soup1();
}
void testStatic() {
Soup1 soup = Soup1.makeSoup();
}
void testSingleton() {
Soup2.access().f();
}
}
  • Soup1 中創建了一個 static 方法,它創建一個新的 Soup1 物件並回傳 reference,如果想要做額外的工作,例如紀錄建立了幾個 Soup1 物件,這時候很有用
  • Soup2 用到了所謂的設計模式 singleton,你始終只能建立它的一個物件,Soup2 類別的物件是作為 Soup2 的一個 static private 成員建立的,所以只能有一個,並且除非透過 public 方法 access() ,否則無法訪問
  • 如果沒幫類別指定一個訪問修飾符,就會得到預設的 package access,這意味著該類別的物件可以由 package 內任何其他 class 來建立,但 package 外則不行
    • 如果該 class 的某個 static 成員為 public,則客戶端仍可以調用該成員,只是不能生成該類別的物件