第三條:用私有構造器或者枚舉類型強化Singleton屬性

Singleton指僅僅被實例化一次的類,Java1.5之前,實現Singleton有兩種方式,這兩種方式都要把構造器保持爲私有的,並導出公有的靜態成員。

第一種:公有靜態成員是個final域

public class Elvis {
    public static final Elvis INSTANCE=new Elvis();
    private Elvis(){};
}

第二種:公有成員方法是一個靜態工廠方法:

public class Elvis {
    private static final Elvis instance=new Elvis();
    private Elvis(){};
    
    public static Elvis getInstance(){
        return instance;
    }
}
私有構造器僅被調用一次,用來實例化公有的靜態final域Elvis,INSTANCE,由於缺少公有的構造器,所以保證了Elvis的全局唯一性,一旦Elvis被實例化,
只會存在一個Elvis實例,但是客戶端可以藉助AccessiableObject.setAccessible方法,通過反射機制,調動私有構造器
Elvis elvis1=Elvis.getInstance();
        Class<Elvis> cls=Elvis.class;
        try {
            Constructor<Elvis> constructor=cls.getDeclaredConstructor(new Class[]{});
            constructor.setAccessible(true);
            try {
                Elvis elvis2=constructor.newInstance(new Object[]{});
                System.out.println(elvis1==elvis2);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

最後輸出:false

還有一種情況是就是序列化和反序列化的時候也會出現多個不同的實例:

File file = new File("singleton");
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream(file));
            Elvis SingletonB1 = Elvis.getInstance();

            oos.writeObject(SingletonB1);
            oos.close();
            ois = new ObjectInputStream(new FileInputStream(file));
            Elvis SingletonB2 = (Elvis) ois.readObject();
            System.out.println(SingletonB1 == SingletonB2);//false

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

輸出:false

這個問題可以提供readResolve方法是爲了每次反序列化一個序列化的實例時,避免去創建一個新的實例。

public class Elvis implements Serializable {
    private static final Elvis instance=new Elvis();
    private Elvis(){};

    public static Elvis getInstance(){
        return instance;
    }
    // 不添加該方法則會出現 反序列化時出現多個實例的問題
    public Object readResolve() {
        return instance;
    }
}

第三種方式:單元素的枚舉類型.

public enum Singletonc implements Serializable {
    INSTANCE;

    private Singletonc() {
    }

    String type;

    public void setType(String name) {
        this.type = name;
    }

    public void getType() {
        System.out.println(type);
    }

    public static void main(String[] args){
        Singletonc.INSTANCE.setType("哈哈哈哈");
        Singletonc.INSTANCE.getType();
    }
}

單元素的枚舉類型已經成爲實現Singleton的最佳方法

發佈了25 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章