在我之前的一篇文章中介绍了怎么实现单例模式:
http://blog.csdn.net/u011499747/article/details/48194431
但是,这是存在问题的。
不考虑反射这种极端情况,还有一种情况会破坏单例模式。
序列化,反序列化!
package cp2;
import java.io.Serializable;
import java.util.Objects;
/**
* Created by dubby on 16/3/25.
*/
public class SerSingleton implements Serializable {
String name;
private SerSingleton(){
System.out.println("Singleton is creating");
}
private static SerSingleton instance = new SerSingleton();
public static SerSingleton getInstance(){
return instance;
}
public static void createString(){
System.out.println("create string in singleton");
}
}
测试代码:
import cp2.SerSingleton;
import junit.framework.Assert;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Created by dubby on 16/3/25.
*/
public class SerSingletonTest {
@Test
public void test() throws Exception{
SerSingleton s1 = null;
SerSingleton s = SerSingleton.getInstance();
FileOutputStream fos = new FileOutputStream("a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (SerSingleton) ois.readObject();
Assert.assertEquals(s,s1);
}
}
结果:
junit.framework.AssertionFailedError:
Expected :cp2.SerSingleton@7ab2bfe1
Actual :cp2.SerSingleton@497470ed
<Click to see difference>
问题来了,怎么解决呢?jdk其实预料到这种情况了。
解决方法:加入readResolve()
在jdk中ObjectInputStream的类中有readUnshared()方法,上面详细解释了原因。我简单描述一下,那就是如果被反序列化的对象的类存在readResolve这个方法,他会调用这个方法来返回一个“array”(我也不明白),然后浅拷贝一份,作为返回值,并且无视掉反序列化的值,即使那个字节码已经被解析。
所以,完整的单例模式是:
package cp2;
import java.io.Serializable;
import java.util.Objects;
/**
* Created by dubby on 16/3/25.
*/
public class SerSingleton implements Serializable {
String name;
private SerSingleton(){
System.out.println("Singleton is creating");
}
private static SerSingleton instance = new SerSingleton();
public static SerSingleton getInstance(){
return instance;
}
public static void createString(){
System.out.println("create string in singleton");
}
private Object readResolve(){
System.out.println("read resolve");
return instance;
}
}