`
lovnet
  • 浏览: 6713093 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

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

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

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


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

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






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


  1. // Singleton with static factory - Page 17
  2. publicclassElvis {
  3. privatestaticfinalElvis INSTANCE =newElvis();
  4. privateElvis() { }
  5. publicstaticElvis getInstance() {returnINSTANCE; }
  6. publicvoidleaveTheBuilding() {
  7. System.out.println("Whoa baby, I'm outta here!");
  8. }
  9. // This code would normally appear outside the class!
  10. publicstaticvoidmain(String[] args) {
  11. Elvis elvis = Elvis.getInstance();
  12. elvis.leaveTheBuilding();
  13. }
  14. }


问题:同上




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



  1. importjava.io.Serializable;
  2. // Serializable singleton with public final field - Page 18
  3. publicclassElvisimplementsSerializable{
  4. publicstaticfinalElvis INSTANCE =newElvis();
  5. privateElvis() { }
  6. publicvoidleaveTheBuilding() {
  7. System.out.println("Whoa baby, I'm outta here!");
  8. }
  9. privateObject readResolve() {
  10. // Return the one true Elvis and let the garbage collector
  11. // take care of the Elvis impersonator.
  12. returnINSTANCE;
  13. }
  14. // This code would normally appear outside the class!
  15. publicstaticvoidmain(String[] args) {
  16. Elvis elvis = Elvis.INSTANCE;
  17. elvis.leaveTheBuilding();
  18. }
  19. }


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


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



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics