用私有构造器或者枚举类型强化Singleton属性

在1.5版本之前可以两种实现Singleton的方法,但是都要把构造器保存为私有的。

1、公有静态成员是个final域

 

 
  1. // Singleton with public final field - Page 17  
  2. public class Elvis {  
  3.     public static final Elvis INSTANCE = new Elvis();  
  4.     private Elvis() { }  
  5.   
  6.     public void leaveTheBuilding() {  
  7.         System.out.println("Whoa baby, I'm outta here!");  
  8.     }  
  9.   
  10.     // This code would normally appear outside the class!  
  11.     public static void main(String[] args) {  
  12.         Elvis elvis = Elvis.INSTANCE;  
  13.         elvis.leaveTheBuilding();  
  14.     }  
  15. }  

 

问题:但是客户端可以通过AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。
AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。 
在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久性机制)以某种通常禁止使用的方式来操作对象。 

2、公有的成员是个静态工厂方法
这种方法很清晰的表明了这个类是一个Singleton

 

 
  1. // Singleton with static factory - Page 17  
  2.   
  3. public class Elvis {  
  4.     private static final Elvis INSTANCE = new Elvis();  
  5.     private Elvis() { }  
  6.     public static Elvis getInstance() { return INSTANCE; }  
  7.   
  8.     public void leaveTheBuilding() {  
  9.         System.out.println("Whoa baby, I'm outta here!");  
  10.     }  
  11.   
  12.     // This code would normally appear outside the class!  
  13.     public static void main(String[] args) {  
  14.         Elvis elvis = Elvis.getInstance();  
  15.         elvis.leaveTheBuilding();  
  16.     }  
  17. }  

 

 

问题:同上

3、实现Singleton类变成可序列化的,仅仅实现序列化是不够的,为了维护并保证Singleton,必须声明所有实例域都是瞬时(transient)的,并提供一个readResolve方法。否则,每次反序列化一个序列的实例时,都会创建一个新的实例。
《The readResolve Method -- 序列化实现readResolve方法的作用》http://blog.csdn.net/partner4java/article/details/7058741

 

 

 
  1. import java.io.Serializable;  
  2.   
  3. // Serializable singleton with public final field - Page 18  
  4. public class Elvis implements Serializable{  
  5.     public static final Elvis INSTANCE = new Elvis();  
  6.     private Elvis() { }  
  7.   
  8.     public void leaveTheBuilding() {  
  9.         System.out.println("Whoa baby, I'm outta here!");  
  10.     }  
  11.   
  12.     private Object readResolve() {  
  13.         // Return the one true Elvis and let the garbage collector  
  14.         // take care of the Elvis impersonator.  
  15.         return INSTANCE;  
  16.     }  
  17.   
  18.     // This code would normally appear outside the class!  
  19.     public static void main(String[] args) {  
  20.         Elvis elvis = Elvis.INSTANCE;  
  21.         elvis.leaveTheBuilding();  
  22.     }  
  23. }  

 

 

4、从JDK 1.5开始,实现Singleton,可以编写一个包含单个元素的枚举类型。
而且可以解决复杂的反序列化或者反射的攻击。
单元素的枚举类型已经成为实现Singleton的最佳方法。

 

 
  1. // Enum singleton - the preferred approach - page 18  
  2. public enum Elvis {  
  3.     INSTANCE;  
  4.   
  5.     public void leaveTheBuilding() {  
  6.         System.out.println("Whoa baby, I'm outta here!");  
  7.     }  
  8.   
  9.     // This code would normally appear outside the class!  
  10.     public static void main(String[] args) {  
  11.         Elvis elvis = Elvis.INSTANCE;  
  12.         elvis.leaveTheBuilding();  
  13.     }  
  14. }  

猜你喜欢

转载自windpoplar.iteye.com/blog/2315907
今日推荐