Effective Java之用私有构造器或者枚举类型强化Singleton属性(三)
1.餓漢式加載
類(lèi)加載時(shí)就創(chuàng)建
public class MaYun { private static Mayun instance = new Mayun(); private static getInstance() { return instance; } private MaYun() { //MaYun誕生要做的事情 } public void splitAlipay() { System.out.println(“Alipay是我的啦!看你丫Yahoo綠眉綠眼的望著。。。”); } }2.懶漢式加載
類(lèi)使用時(shí)加載
public class MaYun { private static MaYun instance = null; private MaYun() { //MaYun誕生要做的事情 } public static synchronized MaYun getInstance() { if (instance == null) { instance = new MaYun(); } return instance; } public void splitAlipay() { System.out.println(“Alipay是我的啦!看你丫Yahoo綠眉綠眼的望著。。。”); } }3.懶漢式的線(xiàn)程安全版(雙重檢驗(yàn)鎖)
public class MaYun { private volatile static MaYun instance; private MaYun (){} public static MaYun getInstance() { if (instance == null) { synchronized (MaYun.class) { if (instance == null) { instance = new MaYun(); } } } return instance; } }在getInstance中做了兩次null檢查,確保了只有第一次調(diào)用單例的時(shí)候才會(huì)做同步,這樣也是線(xiàn)程安全的,同時(shí)避免了每次都同步的性能損耗
4.靜態(tài)內(nèi)部類(lèi)(推薦)
public class MaYun { private static class SigletonHolder { private static final instance = new MaYun(); } public static final getInstance() { return SigletonHolder.instance; } private MaYun() { //MaYun誕生要做的事情 } public void splitAlipay() { System.out.println(“Alipay是我的啦!看你丫Yahoo綠眉綠眼的望著。。。”); } Call:MaYun.getInstance().splitAlipay();加載MaYun類(lèi)時(shí),在類(lèi)的加載階段把靜態(tài)內(nèi)部類(lèi)加載了,也就是利用了classloader的機(jī)制來(lái)保證初始化instance時(shí)只有一個(gè)線(xiàn)程,所以也是線(xiàn)程安全的,同時(shí)沒(méi)有性能損耗,所以這種方法非常推薦。
5.編寫(xiě)一個(gè)包含單個(gè)元素的枚舉類(lèi)型(極力推薦)
public enum MaYun { himself; //定義一個(gè)枚舉的元素,就代表MaYun的一個(gè)實(shí)例 private String anotherField; MaYun() { //MaYun誕生要做的事情 //這個(gè)方法也可以去掉。將構(gòu)造時(shí)候需要做的事情放在instance賦值的時(shí)候: /** himself = MaYun() { * //MaYun誕生要做的事情 * } **/ } public void splitAlipay() { System.out.println(“Alipay是我的啦!看你丫Yahoo綠眉綠眼的望著。。。”); } } Call:MaYun.himself.splitAlipay();我們來(lái)認(rèn)真分析一下這5種方法:
依然可以創(chuàng)建一個(gè)對(duì)象!
解決的方法是添加計(jì)數(shù)器,大于1時(shí)拋出錯(cuò)誤:
而方法5美劇方法可以防止反射攻擊,當(dāng)你試圖通過(guò)反射去實(shí)例化一個(gè)枚舉類(lèi)型的時(shí)候會(huì)拋出IllegalArgumentException異常:
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objectsat java.lang.reflect.Constructor.newInstance(Constructor.java:416)at org.effectivejava.examples.chapter02.item03.enumoration.MaYun.main(MaYun.java:21)從這里看,方法5具有絕對(duì)的優(yōu)勢(shì)!
2.如果上面實(shí)現(xiàn)的Singleton是可以序列化的。那么方法1234加上implements Serializable只保證它可以序列化,為了保證反序列化的時(shí)候,實(shí)例還是Singleton,必須聲明所有的實(shí)例域都是transient的,并且提供 readResolve方法,否則,每次反序列化都會(huì)生成新的實(shí)例。
但是方法5無(wú)償提供了序列化機(jī)制,絕對(duì)防止多次實(shí)例化,又是絕對(duì)的優(yōu)勢(shì)!
這就是方法5值得極力推薦的的原因,同時(shí)jdk1.5以上才能使用的方法但是這種方法用的人太少了!!所以改變從你我開(kāi)始!
總結(jié)
以上是生活随笔為你收集整理的Effective Java之用私有构造器或者枚举类型强化Singleton属性(三)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Effective Java之多个构造参
- 下一篇: Effective Java之通过私有构