反序列化对单例破坏与解决方案
在需要序列化的类加readResolve方法,注意:1、参数要为空,2、返回要为Object类型的方法。3返回的值是 单例实例的引用。
原因参考下面基础核心代码截图
注意哪怕有了readResolve方法也会创建个对象。只不过若有合格的readResolve方法。那么会将内存中指向的地址重新赋值到待返回的引用。
下面是demo
package creational.singleton;
import java.io.Serializable;
public class LazyDoubleCheckSingleton implements Serializable {
private static final long serialVersionUID = 1L;
private LazyDoubleCheckSingleton(){}
/**
* volatile
*/
private static volatile LazyDoubleCheckSingleton instance;
public static LazyDoubleCheckSingleton getInstance(){
if(instance == null){
synchronized (LazyDoubleCheckSingleton.class){
if(instance == null){
instance = new LazyDoubleCheckSingleton();
}
}
}
return instance;
}
/**
* 注意 这里有几个要点(方法名必须是readResolve。参数必须是空,响应类型必须为Object)
* 修饰符,将决定了子类是被反序列化时候是不是创建新对象
* getInheritableMethod()的核心代码 加上static修饰时候是返回null
* if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
return null;
} else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
return meth;
} else if ((mods & Modifier.PRIVATE) != 0) {
return (cl == defCl) ? meth : null;
} else {
return packageEquals(cl, defCl) ? meth : null;
};
* @return
*/
private Object readResolve(){
return instance;
}
// private LazyDoubleCheckSingleton readResolve(){
// return instance;
// }
}
测试类代码
@org.junit.Test
public void testSerializable(){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(bos)) {
LazyDoubleCheckSingleton instance = LazyDoubleCheckSingleton.getInstance();
System.out.println(instance);
objectOutputStream.writeObject(instance);
byte[] byteArray = bos.toByteArray();
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArray));
Object readObject = objectInputStream.readObject();
System.out.println(readObject);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}