HOWTO · Java

Java 中的靜態類

本文介紹 Java 靜態類。

本頁內容

Java 不允許將頂層類別宣告為 static。在另一個類別內宣告的類別則可以使用 static;這種型別稱為靜態巢狀類別。建立它的實例不需要外層類別的實例,而且可以使用外層類別的靜態成員。如果你想建立一個呼叫端無法透過公開 API 建構的工具類別,應改用私有建構子;這是另一種設計模式。

Java 中的靜態巢狀類別是什麼?

靜態巢狀類別是在另一個類別內使用 static 關鍵字宣告的成員型別。static 修飾詞表示巢狀類別的實例不會隱含參照外層類別的物件。這不代表巢狀類別本身無法建立實例。存取它的型別時,會透過外層型別限定,例如 Container.Entry;呼叫其實例方法時,則需要使用該巢狀型別的實例。

靜態巢狀類別可以存取外層類別的靜態成員,包括私有成員。它不能像擁有外層物件一樣,直接參照外層實例的欄位或方法;但如果明確提供外層物件,就可以透過該物件存取。

如何宣告並使用靜態巢狀類別

使用 static 宣告成員類別,接著以外層型別名稱建立它的實例。以下完整範例也示範如何存取外層類別的靜態欄位:

執行這個範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

public class Container {
    private static int count = 3;

    public static class Entry {
        public int value() {
            return count;
        }
    }

    public static void main(String[] args) {
        Container.Entry entry = new Container.Entry();
        System.out.println(entry.value());
    }
}
3

執行範例會輸出 3。修改範例時,請將巢狀類別保留在外層類別內,並在 Container 外使用 Container.Entry 限定其型別。Entry 物件是一般實例,而 count 屬於外層類別本身。

靜態巢狀類別與內部類別的差異

非靜態成員類別通常稱為內部類別。建立內部類別需要外層實例:先建立 Container 物件,再使用 container.new Inner()。內部類別的實例會保留與該外層物件的關聯,因此可以直接使用外層物件的實例成員。

靜態巢狀類別沒有這種隱含關聯。若要讀取外層實例的欄位,必須傳入或以其他方式取得 Container 物件,再透過該參照存取欄位。這兩種巢狀類別都能存取 Java 巢狀型別存取規則所允許的成員;主要差別在於是否會自動取得外層實例。

如何建立無法由一般呼叫端建構的工具類別

工具類別用來整理不需要每個物件各自持有狀態的操作或常數。將這些成員放在一般頂層類別中,對適當的成員加上 static,並加入 private 建構子,讓一般呼叫端無法從類別外呼叫 new。例如,這種模式可寫成 public final class TextTools { private TextTools() {} public static String join(String first, String second) { return first + second; } };呼叫方式則是 TextTools.join("static ", "utility")。

私有建構子會阻止一般外部程式碼建立實例,但不會讓 TextTools 變成靜態類別;Java 不允許頂層類別使用 static。將類別宣告為 final 是可選的,只會限制繼承。只有在設計確實需要這項限制時才使用它;工具方法本身並不要求類別必須是 final。

關於靜態類別的常見誤解

靜態巢狀類別可以建立實例;static 移除的是對外層實例的隱含需求。它的實例方法可以使用自己的實例欄位。外層類別名稱用來限定巢狀型別,而呼叫該型別的實例方法仍需要巢狀類別的物件。

靜態情境無法使用未限定名稱存取外層實例成員,因為沒有自動提供外層物件;但可以透過明確的物件參照存取該成員。同樣地,私有工具類別建構子會阻止類別外的一般呼叫,而不是在所有情況下都讓建構成為不可能。了解這些差異,就能區分 Java 的巢狀類別語法與工具類別模式。