如果你序列化一个单例类,然后两次重构它,那么你就会得到那个单例类的两个实例,除非你实现readResolve()方法,像下面这样:
例1 一个可序列化的单例类

Java代码
import org.apache.log4j.Logger;   
     
public class Singleton implements java.io.Serializable {   
   public static Singleton INSTANCE = new Singleton();   
     
   protected Singleton() {   
      // Exists only to thwart instantiation.    
   

   
   private Object readResolve() {   
            return INSTANCE;    
     
  


上面的单例类实现从readResolve()方法中返回一个唯一的实例;这样无论Singleton类何时被重构,它都只会返回那个相同的单例类实例。

例2测试了例1 的单例类

 

例2 测试一个可序列化的单例类

Java代码
import java.io.*;   
import org.apache.log4j.Logger;   
import junit.framework.Assert;   
import junit.framework.TestCase;   
     
public class SingletonTest extends TestCase {   
   private Singleton sone = null, stwo = null;   
   private static Logger logger = Logger.getRootLogger();   
     
   public SingletonTest(String name) {   
      super(name);   
     


   public void setUp() {   
       sone = Singleton.INSTANCE;   
       stwo = Singleton.INSTANCE;   
     


   public void testSerialize() {   
       logger.info("testing singleton serialization...");    
       writeSingleton();   
       Singleton s1 = readSingleton();   
       Singleton s2 = readSingleton();   
       Assert.assertEquals(true, s1 == s2);[/b]   

    


   private void writeSingleton() {   
      try {   
          FileOutputStream fos = new FileOutputStream("serializedSingleton");   
          ObjectOutputStream oos = new ObjectOutputStream(fos);   
          Singleton s = Singleton.INSTANCE;   
     
          oos.writeObject(Singleton.INSTANCE);   
          oos.flush();   
       }catch(NotSerializableException se) {   
          logger.fatal("Not Serializable Exception: " + se.getMessage());    
       }catch(IOException iox) {   
          logger.fatal("IO Exception: " + iox.getMessage());    
         
     


   private Singleton readSingleton() {   
       Singleton s = null;   
     
      try {   
          FileInputStream fis = new FileInputStream("serializedSingleton");   
          ObjectInputStream ois = new ObjectInputStream(fis);   
          s = (Singleton)ois.readObject();   
       }catch(ClassNotFoundException cnf) {   
          logger.fatal("Class Not Found Exception: " + cnf.getMessage());   
       }catch(NotSerializableException se) {   
          logger.fatal("Not Serializable Exception: " + se.getMessage());   
       }catch(IOException iox) {   
          logger.fatal("IO Exception: " + iox.getMessage());   
        
      return s;   
     


   public void testUnique() {   
       logger.info("testing singleton uniqueness...");   
       Singleton another = new Singleton();   
     
       logger.info("checking singletons for equality");   
       Assert.assertEquals(true, sone == stwo);   
     
  


    前面这个测试案例序列化例1 中的单例类,并且两次重构它。然后这个测试案例检查看是否被重构的单例类实例是同一个对象。下面是测试案例的输出:

Java代码
Buildfile: build.xml   
     
init:   
      [echo] Build 20030422 (22-04-2003 11:32)   
     
compile:   
     
run-test-text:   
      [java] .INFO main: testing singleton serialization...   
      [java] .INFO main: testing singleton uniqueness...   
      [java] INFO main: checking singletons for equality   
     
      [java] Time: 0.1   
     
      [java] OK (2 tests)   


单例模式结束语

    单例模式简单却容易让人迷惑,特别是对于Java的开发者来说。在这篇文章中,作者演示了Java开发者在顾及多线程、类载入器和序列化情况如何实现单例模式。作者也展示了你怎样才能实现一个单例类的注册表,以便能够在运行期指定单例类。