(3):用私有構造器或者列舉型別強化Singleton屬性
阿新 • • 發佈:2019-01-28
在java 1.5版本發行前實現單例一般有兩種方法
(1)靜態成員
私有構造器僅被呼叫一次,用來初始化公有的靜態final域Elvis.INSTANCE。沒有公有的或者受保護的構造器,確保了Elvis的全域性唯一性:一旦初始化了Elvis類,將只存在一個Elvis例項,不多也不少。客戶端的任何行為都不會改變這一點,但要提醒一點:享有特權的客戶端可以藉助於AccessibleObject.setAccessible方法,通過反射機制(見第53條)呼叫私有構造器。如果需要抵禦這種攻擊,可以修改構造器,讓它在被要求建立第二個例項的時候丟擲異常。public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { } public void leaveTheBuilding() {} // This code would normally appear outside the class! public static void main(String[] args) { Elvis elvis = Elvis.INSTANCE; elvis.leaveTheBuilding(); } }
(2)靜態工廠方法
工廠方法的主要優勢在於,它提供了靈活性:在不改變其API的前提下,我們可以改變該類是否應該為Singleton的想法。工廠方法返回該類的唯一例項,但是,它可以很容易被修改,比如改成為每個呼叫該方法的執行緒返回一個唯一的例項。public class Elvis { private static final Elvis INSTANCE = new Elvis(); private Elvis() { } public static Elvis getInstance() { return INSTANCE; } public void leaveTheBuilding() {} public static void main(String[] args) { Elvis elvis = Elvis.getInstance(); elvis.leaveTheBuilding(); } }
在java 1.5後出現了一個新的方法
(3)單元素列舉型別
這種方法在功能上與公有域方法相近,但是它更加簡潔,無償地提供了序列化機制,絕對防止多次例項化,即使是在面對複雜的序列化或者反射攻擊的時候。雖然這種方法還沒有被廣泛採用,但是單元素的列舉型別已經成為實現Singleton的最佳方法。public enum Elvis { INSTANCE; public void leaveTheBuilding() {} public static void main(String[] args) { Elvis elvis = Elvis.INSTANCE; elvis.leaveTheBuilding(); } }