- 第一種方式
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;
}
}