之前明白了 线程安全且延迟加载的单例如何写,有两种,双重检验和静态内部类。然后为了防止反射破坏单例,在私有构造方法里面加入了一个同步变量的判断,确保构造方法只调用一次。但是仍然无法阻止序列化破坏单例,例子:
package gggg;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class S implements Serializable {
private S(){
System.out.println("con");
}
static class SS{
private static S s = new S();
}
public static S instance(){
return SS.s;
}
public static void main(String[] args) {
try {
S s1 = S.instance();
FileOutputStream out = new FileOutputStream("a");
ObjectOutputStream outt = new ObjectOutputStream(out);
outt.writeObject(s1);
FileInputStream in = new FileInputStream("a");
ObjectInputStream inn = new ObjectInputStream(in);
S s2 = (S) inn.readObject();
System.out.print(s1 == s2);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
可以看到这里是false,说明有两个实例。
在readObj底层实现上,是通过反射调用私有构造方法来返回实例的,但是在这段代码后面,还会检测该类是否有一个readResolve()方法,如果有,就返回这个方法返回值。这个方法必然是为了解决序列化破坏单例的,我们可以添加这个方法,让其返回单例。
所以在单例类中添加如下方法:
public Object readResolve(){
return instance();
}
最后再执行,就是true了,说明返回了同一个对象。