關於單例模式,相信你們都全部瞭解,比較經典的實現有餓漢式、藉助內部類、雙重鎖檢測,這些實現能夠保證線程安全,可是在某些特殊狀況下並不可以保證僅僅只有一個單例,由於像序列化、反射攻擊等每每能夠生成新的實例對象,本文將重點分析枚舉單例模式如何防止反射攻擊。java
枚舉單例:安全
public enum Singleton { INSTANCE { @Override protected void read() { System.out.println("read"); } @Override protected void write() { System.out.println("write"); } }; protected abstract void read(); protected abstract void write(); }
以上是一個單例枚舉的例子,而咱們要獲取該實例只須要Singleton.INSTANCE,而且此種方式能夠保證該單例線程安全、防反射攻擊、防止序列化生成新的實例。ide
枚舉單例關於防反射攻擊,固然和枚舉的實現有關,枚舉也是java類,咱們對Singleton的class進行反編譯,能夠獲得一個新的類(對於枚舉的實現不瞭解的能夠補補相關知識):this
反編譯後的類:線程
public abstract class Singleton extends Enum { private Singleton(String s, int i) { super(s, i); } protected abstract void read(); protected abstract void write(); public static Singleton[] values() { Singleton asingleton[]; int i; Singleton asingleton1[]; System.arraycopy(asingleton = ENUM$VALUES, 0, asingleton1 = new Singleton[i = asingleton.length], 0, i); return asingleton1; } public static Singleton valueOf(String s) { return (Singleton)Enum.valueOf(singleton/Singleton, s); } Singleton(String s, int i, Singleton singleton) { this(s, i); } public static final Singleton INSTANCE; private static final Singleton ENUM$VALUES[]; static { INSTANCE = new Singleton("INSTANCE", 0) { protected void read() { System.out.println("read"); } protected void write() { System.out.println("write"); } }; ENUM$VALUES = (new Singleton[] { INSTANCE }); } }
看到了這個類的真身事後,相信不少人對於枚舉單例防反射的的原理就瞭解了:code
//readResolve to prevent another instance of Singleton private Object readResolve(){ return INSTANCE; }
若是寫的有問題,歡迎指正~對象