`
1025250620
  • 浏览: 229996 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java单例 序列化陷阱~

 
阅读更多

序列化是java中一个很常用而且很强大的功能。个人的看法,将java对象保存到磁盘,以后再从磁盘中读出来,这是java最常用到的功能之一。在基本的情况下,序列化能够“简单的起作用(just work)”。然而,随着越来越复杂的对象格式以及设计模式的被采用,透明的对象(transparent object)序列化可以“简单的起作用(just work)”的可能性变得越来越不可能了。在处理一个可控制集合的实例,比如单例和enum,就是序列化需要一些而外帮助的一种场景。 

在单例对象可序列的任何场景,确保单例的对象被使用了是非常重要的。这是通过readresolve()接口来实现的。单例就是一个很好的例子:

 

  1. public final class MySingleton {  
  2.  private MySingleton() { }  
  3.  private static final MySingleton INSTANCE = new MySingleton();  
  4.  public static MySingleton getInstance() { return INSTANCE; }  
  5. }  
 

 

在上面的例子中,仅有一种方法获得MySingleton的实例-那就是使用getInstance()这个方法。然后,在简单的添加一个接口的实现后,这段代码就变得不可用了:

 

  1. public final class MySingleton implements Serializable {  
  2. //.  
 

 

现在通过可序列化的工具,我们可以将一个单例的实例对象写到磁盘,然后再读回来,从而有效地获得一个实例。即使构造函数是私有的,可序列化工具依然可以通过特殊的途径去创建类的一个新的实例。序列化操作提供了一个很特别的钩子(hook)-类中具有一个私有的被实例化的方法readresolve(),这个方法可以确保类的开发人员在序列化将会返回怎样的object上具有发言权。足够奇怪的,readresolve()并不是静态的,但是在序列化创建实例的时候被引用。我们在一分钟内就开始体验这个。下面的例子将说明readresolve()怎样在我们的单例中起作用:

 

  1. public final class MySingleton {  
  2.  private MySingleton() { }  
  3.  private static final MySingleton INSTANCE = new MySingleton();  
  4.  public static MySingleton getInstance() { return INSTANCE; }  
  5.  private Object readResolve() throws ObjectStreamException {  
  6.   // instead of the object we're on,   
  7.   // return the class variable INSTANCE  
  8.   return INSTANCE;   
  9.  }  
  10. }  
 

 

目前为止情形还是蛮不错的。但是在处理多个实例的事情,情形就变得有点复杂了。为了解释这点,我将通过一个类型安全的enmumeration来表现这点。请记住,JDK 5的enum类型已经帮你自动处理了这个readresolve的情况。下面是一个很小的enumeration的例子:

 

  1. public final class Sides {  
  2.  private int value;  
  3.  private Sides(int newVal) { value = newVal; }  
  4.  private static final int LEFT_VALUE = 1;  
  5.  private static final int RIGHT_VALUE = 2;  
  6.  private static final int TOP_VALUE = 3;  
  7.  private static final int BOTTOM_VALUE = 4;  
  8.    
  9.  public static final LEFT = new Sides(LEFT_VALUE);  
  10.  public static final RIGHT = new Sides(RIGHT_VALUE);  
  11.  public static final TOP = new Sides(TOP_VALUE);  
  12.  public static final BOTTOM = new Sides(BOTTOM_VALUE);  
  13.    
  14. }  
 

 

现在,我们来实现序列化,用来决定将返回那个实例的key取决于对象本身被设定的值:

 

  1. public final class Sides implements Serializable {  
  2.  private int value;  
  3.  private Sides(int newVal) { value = newVal; }  
  4.  private static final int LEFT_VALUE = 1;  
  5.  private static final int RIGHT_VALUE = 2;  
  6.  private static final int TOP_VALUE = 3;  
  7.  private static final int BOTTOM_VALUE = 4;  
  8.    
  9.  public static final LEFT = new Sides(LEFT_VALUE);  
  10.  public static final RIGHT = new Sides(RIGHT_VALUE);  
  11.  public static final TOP = new Sides(TOP_VALUE);  
  12.  public static final BOTTOM = new Sides(BOTTOM_VALUE);  
  13.    
  14.  private Object readResolve() throws ObjectStreamException {  
  15.   // Switch on this instance's value to figure out which class variable  
  16.   // this is meant to match  
  17.   switch(value) {  
  18.    case LEFT_VALUE: return LEFT;  
  19.    case RIGHT_VALUE: return RIGHT;  
  20.    case TOP_VALUE: return TOP;  
  21.    case BOTTOM_VALUE: return BOTTOM;    
  22.   }  
  23.   return null;  
  24.  }  
  25. }  
分享到:
评论

相关推荐

    java程序员面试陷阱

    面试官可能会询问如何通过反射访问私有属性或方法,以及其在动态代理、序列化和配置文件加载等方面的应用。 9. **接口与抽象类**:理解接口和抽象类之间的区别,以及何时使用它们,是Java编程的基础。面试官可能会...

    Java解惑中文

    4. Java中的I/O操作,包括文件I/O、网络I/O以及序列化与反序列化。 5. Java线程和并发编程,可能涉及死锁、线程同步、线程池的使用等。 6. Java性能调优,涉及JVM参数设置、算法优化、数据结构选择等。 7. Java安全...

    java爱好者必备JAVA解惑(pdf格式)

    5. **IO流**:文件操作、字节流、字符流、缓冲流、对象序列化等。 6. **多线程**:线程的创建、同步、通信,以及Thread和Runnable接口的使用。 7. **反射机制**:运行时动态加载类、获取类信息、调用方法和构造器等...

    Effective-Java-2nd-Edition-(May-2008).zip_effective java

    13. **序列化**:解释了Java序列化的工作原理,以及如何控制序列化行为,包括实现Serializable接口和使用transient关键字。 14. **预优化的陷阱**:告诫开发者不要过早优化代码,大多数情况下,Java的默认性能已经...

    西安石油大学Java课件

    8. **输入/输出流**:文件读写、对象序列化、网络通信等IO操作。 9. **异常处理**:理解异常体系,学习如何抛出和捕获异常。 10. **多线程编程**:线程的创建、同步、通信,以及线程池的使用。 11. **JavaSE、...

    java经典课件及源码

    5. **IO流**:字节流和字符流的区别,缓冲流的使用,对象序列化,以及NIO(New IO)的新特性。 6. **网络编程**:Socket编程基础,TCP和UDP的区别,以及服务器端和客户端的交互过程。 7. **反射机制**:如何在运行...

    Java实效编程百例

    实例可能包含文件操作、字符流、字节流以及对象序列化的例子。 6. **反射API**:反射允许程序在运行时检查类、接口、字段和方法的信息,实例将展示如何动态调用方法和访问私有成员。 7. **泛型**:泛型提高了代码...

    java面试试题。。。。。。

    IO流与NIO(非阻塞I/O)是处理输入输出的关键,包括文件操作、网络通信、序列化与反序列化等。面试中可能涉及对不同类型的流(字节流、字符流、缓冲流、对象流)的理解和使用,以及NIO在性能优化上的优势。 设计...

    effectiveJava的笔记

    4. **枚举**:介绍枚举类型的强大之处,如枚举的自动序列化、枚举常量之间的比较以及它们可以拥有方法和字段,优于传统的`int`常量。 5. **泛型**:讲解泛型的基本用法,包括类型擦除、边界通配符、类型推断,以及...

    JAVA程序员面试宝典 第4版(带书签 高清扫描版)欧立奇

    5. 输入/输出流:文件操作、对象序列化,以及缓冲流的使用。 二、Java集合框架 1. 集合接口:List、Set、Queue、Map的区别与应用场景。 2. 实现类详解:ArrayList、LinkedList、HashSet、HashMap等的内部实现原理及...

    java--夜未眠<过来人的心得>

    4. **IO流**:字节流、字符流、缓冲流、对象序列化等,以及NIO(New IO)的介绍。 5. **多线程**:线程的创建、同步机制(synchronized、wait/notify、Lock接口)、线程池的使用。 6. **网络编程**:Socket编程,...

    java面试题集(非常好的资源)

    7. **反射机制**:理解如何通过反射动态调用方法、创建对象和访问私有成员,以及其在插件化、序列化和配置文件读取中的应用。 8. **设计模式**:熟悉常见的23种设计模式,如单例、工厂、装饰器、适配器、观察者、...

    毕向东静态06

    - 枚举:最简单且线程安全的实现方式,防止反序列化导致的多实例问题。 视频教程中,毕向东老师可能会通过实际代码示例来讲解这些概念,并讨论它们在实际项目中的应用,帮助学员深入理解字符串操作和单例模式的...

    Java版数据结构与算法.zip

    - **IO流**:文件读写、对象序列化、管道流、缓冲流等。 - **泛型**:类型安全的容器,提高代码复用性。 - **异常处理**:异常分类、抛出和捕获,以及finally块的使用。 - **反射**:运行时动态访问类、接口、...

    某战programmer答案

    6. **IO流**:学习文件操作,包括读写文件、流的分类(字节流和字符流)、缓冲流、对象序列化等。 7. **多线程**:掌握线程的创建(Thread类和Runnable接口)、同步机制(synchronized关键字、wait/notify、Lock...

    PaperTestQ&amp;A笔试综述(20170824152521)

    5. **IO流**:字节流、字符流、缓冲流、对象序列化。 6. **网络编程**:Socket通信、HTTP协议。 7. **JVM内存模型**:堆、栈、方法区、本地方法栈。 8. **设计模式**:单例、工厂、装饰器、观察者等。 这样的笔试...

    howToGuide:我不得不重用它们时往往会忘记的东西的集合

    6. **IO流**:字节流与字符流,缓冲流,对象序列化,以及NIO(非阻塞I/O)。 7. **网络编程**:Socket编程,HTTP客户端和服务端的实现。 8. **反射**:Class类的使用,动态获取类信息,创建对象,调用方法,修改...

    软件工程复习试题 是你必须的

    单元测试、集成测试和系统测试的步骤和方法应烂熟于心,同时了解缺陷管理工具,如JIRA,以及自动化测试工具,如JUnit和Selenium,能够提升测试效率。 最后,软件维护阶段则涉及到软件的升级、优化和废弃。理解软件...

    将军

    Kotlin提供了许多独特的功能,如空安全、类型安全以及单例模式等,这些都使得开发者能够更好地避免编程陷阱,提高代码质量。 首先,让我们深入了解Kotlin的基础。Kotlin是一种静态类型的、现代的、多平台的编程语言...

Global site tag (gtag.js) - Google Analytics