1. 程式人生 > >第3條 建立與銷燬物件——用私有構造器或者列舉型別強化Singleton屬性

第3條 建立與銷燬物件——用私有構造器或者列舉型別強化Singleton屬性

實現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的最佳方法