2017-08-25 45 views
4

我很困惑。我在java中發現了很多Singleton設計模式的實現。其中我發現實現的是:單身設計模式java idioma

public class MySingleton { 

    private static class Loader { 
     static MySingleton INSTANCE = new MySingleton(); 
    } 

    private MySingleton() {} 

    public static MySingleton getInstance() { 
     return Loader.INSTANCE; 
    } 
} 

如下解釋:https://stackoverflow.com。 現在,如果這個實現應該起作用,爲什麼不會出現以下情況?

public class MySingleton { 

    private static final MySingleton INSTANCE = new MySingleton(); 

    private MySingleton() {} 

    public static MySingleton getInstance() { 
     return INSTANCE; 
    } 
} 

我搜索圍繞Java如何處理初始化,但找不到任何顯示後者的代碼將無法正常工作。 取而代之的是,我找到了以下內容:stackoverflow.com,它指出每個靜態初始化發生在類的靜態方法被調用之前,所以當調用訪問INSTANCE(getInstance)的唯一方法時,應該初始化包含單例實例的靜態字段。 所以是的,我真的很困惑:如果這段代碼有效,爲什麼不使用這個更簡單的單例設計模式?

+1

後者確實有效:它是一個* eager *單例,而前者是* lazy *單例。 –

回答

5

這兩個工作都是單身人士的有效實施。
第一個使用延遲初始化。
這意味着只有當客戶端調用getInstance()時才創建單例。
第二個使用一個渴望的初始化。
這意味着只要類加載器加載MySingleton類,就會創建單例。

在實踐中,它並沒有太大的區別,因爲通常getInstance()和單例類加載通常是耦合的。
確實很少有一個客戶類指向一個單例類,而不需要通過getInstance()來請求它的實例。

因此,在一般情況下,更加簡潔的第二種方式(熱切初始化)應該受到青睞。

+0

關於能夠通過反射創建課程的其他實例有什麼擔憂? – nasukkin

+0

@nasukkin這兩個問題都沒有解決這個問題,所以它與這個問題無關。 – Andreas

+0

@nasukkin許多事情可能會被反思改變。沒有增變器的字段,使用'final'修飾符的字段等等......如果你爲客戶提供了一個組件,並且你需要/想要保護類定義和對象狀態,那麼使用單例的枚舉是好的,但它肯定是不夠的。由於公共組件顯然不是問題,所以引用這個問題會比其他問題帶來更多的困惑。 – davidxxx

1

Java內置的單例模式實現是enum。當你定義一個enum時,你聲明並初始化(又名「枚舉」)運行時可能存在的所有實例。原始問題中提供的方法存在漏洞;聰明的用戶可以創建你的「單身」類的新的非託管實例。 (我建議你閱讀他的例子約書亞布洛赫的「有效的Java」的書就如何可以完成此。)

你應該考慮實現你的單身像這樣:

public enum MySingleton { 
    INSTANCE(); 

    /* delcare instance fields here. */ 

    /** constructor; give it params if you need to. */ 
    public MySingleton() { 
     // initialize whatever you need here. 
    } 

    /* methods you'll use go here. */ 
} 

當你需要你的單,您只需將其作爲MySingleton.INSTANCE即可。

+0

語法錯誤:*枚舉構造函數的非法修飾符; * – Andreas

+0

@Andreas你得到語法錯誤,因爲你定義了一個enum寫INSTANCE; (沒有括號) – taran95

+0

@ taran95不,我得到語法錯誤,因爲構造函數是'public',並且只允許'private',*完全像錯誤說的*。 – Andreas