Thinking in Java(5-2) 訪問權限修飾詞解析及其應用
在物件導向程式設計中,封裝(Encapsulation) 是一個關鍵概念。透過封裝,我們可以將資料和方法包裝到類別中,並隱藏其具體實作細節。Java 提供了多種訪問權限修飾詞,讓開發者能夠精確控制類別與成員的可見性,從而提高程式的安全性和可維護性。
訪問權限控制與封裝
訪問權限的控制常被稱為具體實作的隱藏。這種機制不僅可以防止外部直接訪問內部資料,還能避免客戶端程式設計師意外地將內部機制當作可用的介面。
- 設定權限邊界: 將權限的邊界設定在資料型態的內部,確保只有授權的部分才可被外部訪問。
- 分離介面與實作: 客戶端只能與公開的介面互動,無法直接操縱內部的實作細節。這樣,即使我們更改了非
public
的部分,也不會影響到客戶端的程式碼。
為了增進程式碼的清晰度,建議按照以下順序定義類別的成員:
public class OrganizedByAccess {
// Public methods
public void pub1() { /* ... */ }
public void pub2() { /* ... */ }
public void pub3() { /* ... */ }
// Protected methods
protected void prot1() { /* ... */ }
// Package-private methods (no modifier)
void pack1() { /* ... */ }
// Private methods
private void priv1() { /* ... */ }
private void priv2() { /* ... */ }
private void priv3() { /* ... */ }
// Private fields
private int i;
// ...
}
這種排列方式的好處是,使用者可以從上到下閱讀,先看到對他們最重要的 public
成員,然後依次深入了解。
類別的訪問權限設定
在 Java 中,訪問權限修飾詞不僅可以應用於類別的成員,也可以用來控制整個類別的可見性。
控制類別的訪問權限
要控制某個類別的訪問權限,修飾詞需放在 class
關鍵字之前。
package access;
public class Widget {}
客戶端可以透過以下方式訪問 Widget
類別:
import access.Widget;
// 或
import access.*;
注意事項:
- 每個編譯單元(檔案)只能有一個
public
類別。 如果有多個public
類別,編譯器會報錯。 public
類別的名稱必須與檔案名稱完全匹配(包含大小寫)。 例如,Widget
類別必須存放在Widget.java
檔案中。若檔案命名為WIDGET.java
或widget.java
,編譯器將無法通過。- 編譯單元可以沒有
public
類別。 在這種情況下,檔案命名不受限制。
類別的訪問修飾詞選擇
對於類別本身,Java 只允許兩種訪問權限:
public
- 預設(package-private,沒有修飾詞)
類別不能被宣告為 private
或 protected
,除非它是內部類別。
範例:
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
類別: 建構子為private
,無法直接創建物件。透過public
的靜態方法makeSoup()
,可以創建並取得Soup1
的實例。Soup2
類別: 採用了單例模式(Singleton Pattern),確保類別只能有一個實例。ps1
是一個private static
成員,透過public
方法access()
取得實例。Lunch
類別: 測試了如何使用上述兩個類別。直接創建Soup1
會失敗,但可以透過makeSoup()
方法。Soup2
的實例則透過access()
方法取得。
預設(package-private)訪問權限
如果類別沒有指定訪問修飾詞,則具有預設的 package-private 訪問權限。
- 可見性: 只能被同一個 package 中的其他類別訪問。
- 用途: 這種設定允許在 package 內共享類別,但防止外部直接訪問。
注意:
- 即使類別的某個
static
成員是public
,外部客戶端仍然無法創建該類別的實例,但可以調用其public static
成員。
小結
透過正確使用 Java 的訪問權限修飾詞,我們可以精確地控制類別和成員的可見性,從而實現資料的封裝和介面與實作的分離。這不僅提高了程式的安全性,也使得程式碼更易於維護和擴展。
Comments ()