序列化破坏单例模式演示
import java.io.Serializable;
public class HungrySingleton implements Serializable{
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
}
public class Test {
public static void main(String[] args) throws Exception {
HungrySingleton instance = HungrySingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance);
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
HungrySingleton newInstance = (HungrySingleton) ois.readObject();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance == newInstance);
}
}
输出:
designpattern.creational.singleton.serializable.HungrySingleton@27bc2616
designpattern.creational.singleton.serializable.HungrySingleton@443b7951
false
解决方案
- 添加 readResolve() 方法;
import java.io.Serializable;
public class HungrySingleton implements Serializable{
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
private Object readResolve() {
return hungrySingleton;
}
}
public class Test {
public static void main(String[] args) throws Exception {
HungrySingleton instance = HungrySingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance);
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
HungrySingleton newInstance = (HungrySingleton) ois.readObject();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance == newInstance);
}
}
输出:
designpattern.creational.singleton.serializable.HungrySingleton@27bc2616
designpattern.creational.singleton.serializable.HungrySingleton@27bc2616
true
原理解析 & JDK源码跟踪
-
调用ObjectInputStream的readObject()方法,从文件中反序列化出newInstance对象;
1.png -
readObject()方法调用的是readObject0()方法;
2.png -
readObject0()调用readOrdinaryObject(unshared)方法;
3.png
4.1 desc是java.io.ObjectStreamClass类对象,是类在序列化时的描述符;
4.2 通过desc判断待反序列化的类是否是可实例化的;

-
通过desc判断待反序列化的类(HungrySingleton)是否有名为readResolve的方法;
5.png -
返回结果说明描述符desc描述的类HungrySingleton是有readResolve()方法的;
6.png -
利用描述符desc进入反射调用的地方;
7.png -
反射调用HungrySingleton的readResolve()方法;
8.png -
HungrySingleton的readResolve()方法被调用;
9.png -
回到main方法中调用的ObjectInputStream的readObject()方法;
10.png -
得到反序列化的结果,就是HungrySingleton中的单例hungrySingleton,而不是新的HungrySingleton实例;
11.png