首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

單例模式最佳實踐:靜態內部類 (Static Inner Class) 寫法

     編輯:Java 相關知識

前言

單例模式確保類別全域僅有一個實例,並提供全域存取點。在 Java/C# 中,靜態內部類 (Static Nested Class) 寫法結合了延遲初始化、線程安全、程式碼簡潔 三大優勢,是公認最佳實踐之一 (Effective Java Item 3)。

Java 實作


public final class Singleton {
    // 私有建構子,防止外部實例化
    private Singleton() {}

    // 靜態內部類持有唯一實例
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }

    // 全域存取點
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }

    // 業務方法
    public void doSomething() {
        System.out.println("Singleton doing work...");
    }
}

C# 實作


public sealed class Singleton
{
    // 私有建構子
    private Singleton() {}

    // 靜態內部類 (巢狀類別)
    private static class Holder
    {
        // .NET 保證靜態建構子只執行一次,且線程安全
        internal static readonly Singleton Instance = new Singleton();
    }

    public static Singleton Instance => Holder.Instance;

    public void DoSomething() => Console.WriteLine("Singleton working...");
}

為什麼這是最佳寫法?

特性靜態內部類寫法雙重檢查鎖定 (DCL)急切初始化
線程安全✅ 類別載入機制天然保證✅ 需 volatile + 鎖定✅ 但無延遲
延遲初始化✅ 首次呼叫 getInstance() 才載入 Holder✅❌ 類別載入即建立
效能✅ 無同步開銷,JIT 內聯優化⚠️ volatile 讀取開銷✅ 最快但無延遲
程式碼簡潔度✅ 極簡❌ 複雜易錯✅ 簡單但無延遲
序列化安全⚠️ 需實作 readResolve⚠️ 同上⚠️ 同上
反射攻擊⚠️ 可用 Enum 單例防禦⚠️ 同上⚠️ 同上

核心機制解析

  • 類別載入時機:JVM/CLR 保證類別首次被主動使用時才初始化。Holder 類別只有在呼叫 getInstance() 存取 Holder.INSTANCE 時才會被載入初始化。
  • 線程安全:類別初始化由類別載入器鎖定同步,無需額外 synchronized/lock。
  • 最終性:final (Java) / readonly (C#) 確保實例不可重新指派。

進階:防禦反射與序列化破壞


// Java: 防反射
private Singleton() {
    if (Holder.INSTANCE != null) {
        throw new IllegalStateException("Already initialized");
    }
}

// Java: 防序列化
private Object readResolve() {
    return Holder.INSTANCE;
}

// C#: 防反射 (較難完全防禦,可拋出例外)
private Singleton() {
    if (Holder.Instance != null) throw new InvalidOperationException("Singleton already created");
}

// C#: 序列化建議標記 [Serializable] 並實作 ISerializable 或用 NonSerialized

何時選擇其他寫法?

  • Enum 單例 (Java):public enum Singleton { INSTANCE; } — 絕對防反射、防序列化、線程安全、簡潔。首選若不需繼承/延遲初始化。
  • 急切初始化:實例建立成本極低、必定會被使用、無循環依賴風險。
  • 雙重檢查鎖定:極少數需手動控制初始化時機、且環境不支援靜態內部類語法 (極舊版本)。

總結

靜態內部類單例 是延遲初始化、線程安全、高效能、程式碼極簡的完美平衡。Java/C# 通用,強烈建議作為預設選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved