如何在 Java 中製作單例? 初始化類型、比較和要記住的要點
已發表: 2020-10-07Java 中的單例類被定義為只有一個對象的類,即只有一個類的實例。 將實例限制為每個類只有一個有助於編寫只需要一個類實例的特定程序。 單例類的唯一實例被賦予一個全局訪問點。
單例類是 Java 編程中重要的設計模式之一。 單例類有助於限制資源和優化資源; 它在數據庫連接或套接字中被大量使用。 單例類有實現語法,優秀的開發者必須知道。 讓我們看看 Java 中單例類的實現。
從世界頂級大學在線學習軟件工程師課程。 獲得行政 PG 課程、高級證書課程或碩士課程,以加快您的職業生涯。
閱讀: Java 架構和組件解釋
目錄
初始化
Java 中單例的初始化是通過私有構造函數完成的。 私有構造函數有助於其他類無法創建與單例類相同的實例。 Java中有五種類型的單例類初始化,如下所示:
1.渴望初始化
創建了一個通常命名為 getInstance() 的公共方法。 此方法將有助於只為創建類的實例提供一個入口點,從而使其成為單例類。 急切初始化中的類實例是在類加載時創建的。

這種類型的初始化技術會自動創建類的實例,即使用戶沒有使用它。 這可能會導致內存問題和代碼中不必要的長度。 為了解決內存洩漏問題,讓我們看看另一種類型的 Java 中單例類的初始化技術。
2. 延遲初始化
類的實例在方法 getInstance () 本身中以延遲初始化的方式初始化。 惰性初始化中的方法會檢查類的實例是否被創建,如果沒有創建,則只創建一個實例,從而解決內存洩漏問題。
在延遲初始化中創建的方法是靜態的並且具有返回類型對象。 在第一次調用 getInstance() 方法之前,不會創建延遲初始化中的單例實例。
3. 使用雙鎖方法進行延遲初始化
此方法在多個線程時使用。 如果我們在程序中使用了兩個線程,並且在實例為空的情況下啟動時都可以通過'if'語句訪問它們,則會產生衝突的情況,您可能會發現錯誤。
這個問題通過雙鎖方法解決了,在這種方法中,一次只有一個線程進入同步塊中以初始化實例,而另一個線程被阻塞。 當第一個線程退出同步塊時,只有第二個線程進入並創建另一個實例。 默認情況下,第二個線程不檢查實例是否為非空。
4. 延遲加載方法
嵌套內部類是在此方法中創建的,並按照 JLS(Java 語言規範)的原則工作。 類中沒有靜態數據成員; JVM 不會創建該類的實例。 只有當我們調用 getInstance() 方法時,才會按需創建實例。

您不需要同步初始化和加載方法,因為此方法有助於自動同步所有獲取 Instance() 的調用。
5.枚舉方法
在上述方法中,仍然可以通過序列化和反射創建單例類的多個實例。 在製作嚴格的單例類的情況下,可以使用這種方法。 此方法中使用枚舉字段,它是一個常量,僅在編譯時運行。
Enum 是 Enum 類型的實例,只有在代碼中第一次調用/調用 Enum 類型時才會構造。 該方法限制了實例的克隆,並製作了一個完美的單例類。
另請閱讀:您今天應該檢查的 12 大 Java 模式程序
序列化和反射
序列化有助於將 Java 對像從一個 JVM(Java 虛擬機)傳輸到另一個。 序列化是用於創建類的多個實例的方法之一。 序列化將對象轉換為字節流,然後傳輸完成。
字節流有助於使用反序列化過程在其他一些 JVM 中重新創建對象。 它幫助多個系統在它們之間進行通信和共享對象。 它有助於跨 JVM 同步,因為對象將在不同的 JVM 中工作。
反射也是Java中克隆對象的一種方法。 反射是一個 API,它可以幫助我們了解任何未知對象的類和可以通過對象訪問的特定類的方法。 反射被程序員廣泛用於在運行時修改類和方法的行為。
反射中用到的三個主要命令是getClass()知道對象所屬的類,getConstructors()得到對象所屬類的公共構造函數,getMethods()知道被觀察類的公共方法。
普通班與單身班
Java 中的標準類使用構造函數來初始化自身,而我們使用 getInstance() 方法來初始化單例類。 我們也可以使用相同的類和方法名。 我們首先為普通類創建一個對象,然後我們使用它的方法和屬性。
相反,在單例類中,我們使用類的靜態屬性創建一個實例,並且在整個代碼中的任何時候,該特定類都將只返回一個實例。
除了單例類的許多優點之外,如果對象和方法緊密耦合,也存在一些漏洞,例如單例類篡改單元測試方法。 在這種情況下,您必須將一個功能齊全的類專用於單例。
隱藏的依賴項有時也由單例類創建,因為單例類的引用被傳遞給其他方法並且它不是完全透明的,因此編碼人員/開發人員很難跟踪方法和類。 在創建單例模式之前,應牢記這些缺點,並應盡量減少它。
製作完美單例類的要點
1. 做一個完美的單例類應該關注的點如下:
2. 如果你在一個單例類中創建多個線程,那麼確保所有線程不應該同時初始化單例類。 應該嘗試製作線程安全的單例類。

3. 通過在運行時更改構造函數對公眾的可見性並確保任何特定的單例類只有一個實例,使您的單例類反射證明。
4. 如果有多個線程,可以使用 volatile 修飾符,防止一個線程查看其他線程的初始化狀態。 volatile 修飾符作用於happens-before 關係,其中寫入發生在線程中,然後任何其他線程可以讀取它。
必讀:適合初學者的有趣 Java 項目創意
結論
單例類用於與數據庫或您想要控制類的方法和實例的任何程序建立自定義連接。
如果您想提高您的 Java 技能,您需要掌握這些 Java 項目。 如果您有興趣了解有關 Java、全棧開發的更多信息,請查看 upGrad 和 IIIT-B 的軟件開發執行 PG 計劃 - 全棧開發專業化,該計劃專為工作專業人士設計,提供 500 多個小時的嚴格培訓,9 + 項目和任務、IIIT-B 校友身份、實用的實踐頂點項目和頂級公司的工作協助。