單例模式 原

  • 第一種方式
public class SingletonA {
    public static final SingletonA INSTANCE = new SingletonA();

    private SingletonA(){
        //do something
    }
}
  • 第二種方式
public class SingletonB {
    private static final SingletonB INSTANCE = new SingletonB();

    private SingletonB(){
        //do something
    }
    public static SingletonB getInstance(){
        return INSTANCE;
    }
}

但是上述兩種方式都存在一個問題:享有特權的客戶端可以藉助AccessibleObject.setAccessible方法,通過反射機制調用私有構造器來實例化多個不同的實例

 @Test
    public void test(){
        SingletonA singletonA = SingletonA.INSTANCE;
        Class<SingletonA> cls = SingletonA.class;
        try {
            Constructor<SingletonA> constructor = cls.getDeclaredConstructor(new Class[]{});
            constructor.setAccessible(true);
            SingletonA singletonA1 = constructor.newInstance(new Object[]{});

            System.out.println(singletonA == singletonA1);  //false
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

在《Effective Java中文版 第2版》一書中指出

從java 1.5發行版本起,實現Singleton還有第三種方法。只需編寫一個包含單個元素的枚舉類型。這種方法在功能上與公有域方法相近,但是它更簡潔,無償地提供了序列化機制,絕對防止多次實例化,即使在面對複雜的序列化或者反射攻擊的時候。雖然這種方法話沒有廣泛採用,但是單元素的枚舉類型已經成爲實現Singleton的最佳方法。

public enum  EnumSingleton implements Serializable {
    INSTANCE;
    private String filed;

    public String getFiled() {
        return filed;
    }

    public void setFiled(String filed) {
        this.filed = filed;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章