《Java程序性能优化--让你的Java程序更快、更稳定》,没有理解作者下面标红的话,知识,经验有限设计模式-单例模式学习中的疑问_java

2.1.1  单例模式(3)

通常情况下,用以上方式实现的单例已经可以确保在系统中只存在唯一实例了。但仍然有例外情况,可能导致系统生成多个实例,比如,在代码中,通过反射机制,强行调用单例类的私有构造函数,生成多个单例。考虑到情况的特殊性,本书中不对这种极端的方式进行讨论。但仍有些合法的方法,可能导致系统出现多个单例类的实例。

一个可以被串行化的单例:

  1. public class SerSingleton implements java.io.Serializable{  

  2.    String name;  

  3.    private SerSingleton() {  

  4.        System.out.println("Singleton is create");  

  5.                                        //创建单例的过程可能会比较慢  

  6. name="SerSingleton";  

  7.    }  

  8.    private static SerSingleton instance = new SerSingleton();  

  9.    public static SerSingleton getInstance() {  

  10.        return instance;  

  11.    }  

  12.    public static void createString(){  

  13.        System.out.println("createString in Singleton");  

  14.    }  

  15.    private Object readResolve(){       //阻止生成新的实例,总是返回当前对象  

  16.        return instance;    

  17.    }    

  18. }  


测试代码如下:

  1. @Test  

  2. public void test() throws Exception {  

  3.    SerSingleton s1 = null;  

  4.    SerSingleton s = SerSingleton.getInstance();  

  5.    //先将实例串行化到文件  

  6.    FileOutputStream fos = new FileOutputStream("SerSingleton.txt");  

  7.    ObjectOutputStream oos = new ObjectOutputStream(fos);  

  8.    oos.writeObject(s);  

  9.    oos.flush();  

  10.    oos.close();  

  11.    //从文件读出原有的单例类  

  12.    FileInputStream fis = new FileInputStream("SerSingleton.txt");  

  13.    ObjectInputStream ois = new ObjectInputStream(fis);  

  14. s1 = (SerSingleton) ois.readObject();  

  15.    Assert.assertEquals(s, s1);  

  16. }  

使用一段测试代码测试单例的串行化和反串行化,当去掉SerSingleton代码中加粗的readReslove()函数时,以下测试代码抛出异常:


  1. junit.framework.AssertionFailedError: expected:javatuning.ch2.singleton.  

  2. serialization.SerSingleton@5224ee  

  3. but was:javatuning.ch2.singleton.serialization.SerSingleton@18fe7c3  

说明测试代码中s和s1指向了不同的实例,在反序列化后,生成多个对象实例。而加上readReslove()函数的,程序正常退出。说明,即便经过反序列化,仍然保持了单例的特征。事实上,在实现了私有的readReslove()方法后,readObject()已经形同虚设,它直接使用readReslove()替换了原本的返回值,从而在形式上构造了单例。

注意:序列化和反序列化可能会破坏单例。一般来说,对单例进行序列化和反序列化的场景并不多见,但如果存在,就要多加注意。