1、公有静态成员是个final域
- // Singleton with public final field - Page 17
- public class Elvis {
- public static final Elvis INSTANCE = new Elvis();
- private Elvis() { }
- public void leaveTheBuilding() {
- System.out.println("Whoa baby, I'm outta here!");
- }
- // This code would normally appear outside the class!
- public static void main(String[] args) {
- Elvis elvis = Elvis.INSTANCE;
- elvis.leaveTheBuilding();
- }
- }
问题:但是客户端可以通过AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。
AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。
在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久性机制)以某种通常禁止使用的方式来操作对象。
2、公有的成员是个静态工厂方法
这种方法很清晰的表明了这个类是一个Singleton
- // Singleton with static factory - Page 17
- public class Elvis {
- private static final Elvis INSTANCE = new Elvis();
- private Elvis() { }
- public static Elvis getInstance() { return INSTANCE; }
- public void leaveTheBuilding() {
- System.out.println("Whoa baby, I'm outta here!");
- }
- // This code would normally appear outside the class!
- public static void main(String[] args) {
- Elvis elvis = Elvis.getInstance();
- elvis.leaveTheBuilding();
- }
- }
问题:同上
3、实现Singleton类变成可序列化的,紧紧实现序列化是不够的,为了维护并保证Singleton,必须声明所有实例域都是瞬时(transient)的,并提供一个readResolve方法。否则,每次反序列化一个序列的实例时,都会创建一个新的实例。
《The readResolve Method -- 序列化实现readResolve方法的作用》http://blog.csdn.net/partner4java/article/details/7058741
- import java.io.Serializable;
- // Serializable singleton with public final field - Page 18
- public class Elvis implements Serializable{
- public static final Elvis INSTANCE = new Elvis();
- private Elvis() { }
- public void leaveTheBuilding() {
- System.out.println("Whoa baby, I'm outta here!");
- }
- private Object readResolve() {
- // Return the one true Elvis and let the garbage collector
- // take care of the Elvis impersonator.
- return INSTANCE;
- }
- // This code would normally appear outside the class!
- public static void main(String[] args) {
- Elvis elvis = Elvis.INSTANCE;
- elvis.leaveTheBuilding();
- }
- }
4、从JDK 1.5开始,实现Singleton,可以编写一个包含单个元素的枚举类型。
而且可以解决复杂的反序列化或者反射的攻击。
单元素的枚举类型已经成为实现Singleton的最佳方法。
- // Enum singleton - the preferred approach - page 18
- public enum Elvis {
- INSTANCE;
- public void leaveTheBuilding() {
- System.out.println("Whoa baby, I'm outta here!");
- }
- // This code would normally appear outside the class!
- public static void main(String[] args) {
- Elvis elvis = Elvis.INSTANCE;
- elvis.leaveTheBuilding();
- }
- }