HOWTO · Java

Java 單例類

本教程介紹 Java 單例類。它還演示了為什麼它很重要,如何使用不同的設計模式編寫 Java 單例類。

本頁內容

本教程將在定義級別討論單例類並強調其重要性。我們將描述編寫 Java 單例類的各種設計模式,並藉助程式碼示例對其進行解釋。

Java 中的單例類

Java 單例類允許我們一次只建立該類的一個例項,該例項通過這個單一例項(也稱為類的物件)全域性服務於所有類。單例類不同於用於特定目的的普通類。

它包括避免類的不必要的例項化並確保一次只存在一個物件。它可以節省記憶體並加快工作速度。

請參閱下面的程式碼,其中我們有 ABC 和 XYZ 類。ABC 類有一個名為 method1 的方法,它列印字串 "Hi"。

我們在 XYZ 類中建立類 ABC 的例項來呼叫駐留在類 ABC 中的 method1,我們建立另一個名為 ABC 的例項並再次呼叫 method1 以在下面列印"Hi" XYZ 類。現在,我們有兩個名為 object1 和 object2 的例項(物件),它們擁有不同的引用,但呼叫同一類的相同函式。

我們建立了類 ABC 的兩個物件,它們是類的不必要例項化。我們可以對單個物件做同樣的工作。

其次,每當我們建立一個物件時,它都會佔用記憶體中的空間,這意味著我們通過建立同一個類的多個物件來浪費記憶體。這就是我們使用單例類來避免這些情況的地方。

示例程式碼:

public class ABC {
  // constructor
  public ABC() {}
  // method1
  public void method1() {
    System.out.println("Hi");
  }
}

public class XYZ {
  // first instance of ABC class
  ABC object1 = new ABC();
  object1.method1();

  // second instance of ABC class
  ABC object2 = new ABC();
  object2.method1();
}

單例類在各種應用程式中非常有用,包括日誌記錄、執行緒池、配置設定、快取、資料庫應用程式等。

在 Java 中使用各種方法使用單例類

在 Java 程式設計中編寫單例類有多種方法,計算機程式設計師可以從中選擇。但是所有方法都屬於以下單例類的任何一種設計模式。

  1. 延遲初始化
  2. 早期初始化

對於我們在編寫單例類時使用的任何方法,都應考慮以下因素。

  1. 類的建構函式必須是 private。
  2. 單例類必須有一個靜態方法來返回這個(單例)類例項。

使用延遲初始化方法的 Java 單例類

示例程式碼(Singleton.java):

class Singleton {
  private static Singleton object = null;
  public String message;

  private Singleton() {
    message = "Hi I live in the Singleton class";
  }

  public static Singleton getInstance() {
    if (object == null)
      object = new Singleton();

    return object;
  }
}

示例程式碼(Test.java):

public class Test {
  public static void main(String args[]) {
    Singleton obj1 = Singleton.getInstance();
    Singleton obj2 = Singleton.getInstance();
    Singleton obj3 = Singleton.getInstance();

    System.out.println("Hashcode of obj1 is " + obj1.hashCode());
    System.out.println("Hashcode of obj2 is " + obj2.hashCode());
    System.out.println("Hashcode of obj3 is " + obj3.hashCode());

    if (obj1 == obj2 && obj2 == obj3) {
      System.out.println("Three instances reference to the same memory location");
    } else {
      System.out.println("All are not referencing to the same memory location");
    }
  }
}

輸出:

Hashcode of obj1 is 1490180672
Hashcode of obj2 is 1490180672
Hashcode of obj3 is 1490180672
Three instances reference to the same memory location

在此方法中,僅在需要時建立類物件。使用這種方法,我們可以避免對 Singleton.java 類進行不必要的例項化。

在 Singleton.java 類中,我們建立了該類的 private static 物件(例項),但不對其進行初始化。然後,我們編寫一個 private 建構函式,確保沒有其他類可以呼叫其預設建構函式(public)來建立物件。

最後,我們編寫了一個 static 方法來檢查 Singleton.java 類的例項,如果它是 null,它只建立這個類的例項。在 Test.java 類中,我們可以通過建立不同的物件來確認,以確保每次只建立和呼叫一個例項。

使用早期初始化方法的 Java 單例類

示例程式碼(Singleton.java):

class Singleton {
  private static final Singleton object = new Singleton();
  public String message;

  private Singleton() {
    message = "Hi I live in the Singleton class";
  }

  public static Singleton getInstance() {
    return object;
  }
}

示例程式碼(Test.java):

public class Test {
  public static void main(String args[]) {
    Singleton obj1 = Singleton.getInstance();
    Singleton obj2 = Singleton.getInstance();
    Singleton obj3 = Singleton.getInstance();

    System.out.println("Hashcode of obj1 is " + obj1.hashCode());
    System.out.println("Hashcode of obj2 is " + obj2.hashCode());
    System.out.println("Hashcode of obj3 is " + obj3.hashCode());

    if (obj1 == obj2 && obj2 == obj3) {
      System.out.println("Three instances reference to the same memory location");
    } else {
      System.out.println("All are not referencing to the same memory location");
    }
  }
}

輸出:

Hashcode of obj1 is 1490180672
Hashcode of obj2 is 1490180672
Hashcode of obj3 is 1490180672
Three instances reference to the same memory location

在 Singleton.java 類中,我們建立該類的 private static final 例項並對其進行初始化。然後,我們編寫一個 private 建構函式和一個靜態方法來返回這個類的例項。

請記住,Signleton.java 類例項將在載入時建立。我們還可以將類的例項設定為 public static final 而不是 private static final,以直接訪問該類。

此外,我們有相同的 Test.java 類,它列印並確保每次只呼叫一個例項。