《Java程序性能优化--让你的Java程序更快、更稳定》,没有理解作者下面标红的话,知识,经验有限
2.1.1 单例模式(3)
通常情况下,用以上方式实现的单例已经可以确保在系统中只存在唯一实例了。但仍然有例外情况,可能导致系统生成多个实例,比如,在代码中,通过反射机制,强行调用单例类的私有构造函数,生成多个单例。考虑到情况的特殊性,本书中不对这种极端的方式进行讨论。但仍有些合法的方法,可能导致系统出现多个单例类的实例。
一个可以被串行化的单例:
public class SerSingleton implements java.io.Serializable{
String name;
private SerSingleton() {
System.out.println("Singleton is create");
//创建单例的过程可能会比较慢
name="SerSingleton";
}
private static SerSingleton instance = new SerSingleton();
public static SerSingleton getInstance() {
return instance;
}
public static void createString(){
System.out.println("createString in Singleton");
}
private Object readResolve(){ //阻止生成新的实例,总是返回当前对象
return instance;
}
}
测试代码如下:
@Test
public void test() throws Exception {
SerSingleton s1 = null;
SerSingleton s = SerSingleton.getInstance();
//先将实例串行化到文件
FileOutputStream fos = new FileOutputStream("SerSingleton.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s);
oos.flush();
oos.close();
//从文件读出原有的单例类
FileInputStream fis = new FileInputStream("SerSingleton.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (SerSingleton) ois.readObject();
Assert.assertEquals(s, s1);
}
使用一段测试代码测试单例的串行化和反串行化,当去掉SerSingleton代码中加粗的readReslove()函数时,以下测试代码抛出异常:
junit.framework.AssertionFailedError: expected:javatuning.ch2.singleton.
serialization.SerSingleton@5224ee
but was:javatuning.ch2.singleton.serialization.SerSingleton@18fe7c3
说明测试代码中s和s1指向了不同的实例,在反序列化后,生成多个对象实例。而加上readReslove()函数的,程序正常退出。说明,即便经过反序列化,仍然保持了单例的特征。事实上,在实现了私有的readReslove()方法后,readObject()已经形同虚设,它直接使用readReslove()替换了原本的返回值,从而在形式上构造了单例。
注意:序列化和反序列化可能会破坏单例。一般来说,对单例进行序列化和反序列化的场景并不多见,但如果存在,就要多加注意。