第3條 建立與銷燬物件——用私有構造器或者列舉型別強化Singleton屬性
阿新 • • 發佈:2019-01-30
實現Singleton有以下三種方法。
1、將公有靜態成員做成final域:
public class Elvis { public static final Elvis INSTANCE = newElvis(); private Elvis() { } public void leaveTheBuilding() { System.out.println("Whoa baby, I'moutta here!"); } public static void main(String[] args) { Elvis elvis = Elvis.INSTANCE; elvis.leaveTheBuilding(); } }
2、將公有成員做成靜態工廠方法:
public class Elvis { private static final Elvis INSTANCE = newElvis(); private Elvis() { } public static Elvis getInstance() { returnINSTANCE; } public void leaveTheBuilding() { System.out.println("Whoa baby, I'moutta here!"); } public static void main(String[] args) { Elvis elvis = Elvis.getInstance(); elvis.leaveTheBuilding(); } }
3、單元素列舉型別:
public enum Elvis { INSTANCE; public void leaveTheBuilding() { System.out.println("Whoa baby, I'moutta here!"); } // This code would normally appear outsidethe class! public static void main(String[] args) { Elvis elvis = Elvis.INSTANCE; elvis.leaveTheBuilding(); } }
4、比較:
1)需要注意的是,將公有靜態成員做成final域享有特權的客戶端可以藉助AccessibleObject.setAccessible方法,通過反射機制呼叫私有構造器。如果要抵禦這種攻擊,可以修改構造器,讓它在被要求建立第二個例項的時候丟擲異常。
2)將公有靜態成員做成final域和將公有成員做成靜態工廠方法時,為了使Singleton類變成可序列化的,僅僅在宣告上加上“implements Serializable”是不夠的。為了維護並保證Singleton,必須宣告所有例項域都是瞬時的(transient),並提供一個readResolve方法。否則,每次反序列化一個序列化的例項時,都會建立一個新的例項。
3)單元素列舉型別更加簡潔、無償的提供了序列化機制,絕對防止多次例項化,即使是在面對複雜的序列化或者反射攻擊時;它已經成為實現Singleton的最佳方法。