反序列化破坏单例
public class HungrySingleton implements Serializable {
private static final HungrySingleton singleton;
private static final long serialVersionUID = 2389789839637172279L;
private HungrySingleton(){}
static {
singleton = new HungrySingleton();
}
public static HungrySingleton getInstance(){
return singleton;
}
/**
* readResolve方法,如果没这个方法,就反序列化就会破坏单例。
* 有这个方法,反序列化就不会破坏单例。
* 这个方法的方法名一定要是:readResovle()
* @return
*/
public Object readResolve(){
return singleton;
}
}
为什么写了readResolve方法,反序列化就不会破坏单例呢?原因如下:
ObjectInputStream的readOrdinaryObject(boolean unshared)方法
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
desc.checkDeserialize();
Class<?> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}
Object obj;
try {
obj = desc.isInstantiable() ? desc.newInstance() : null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(
desc.forClass().getName(),
"unable to create instance").initCause(ex);
}
passHandle = handles.assign(unshared ? unsharedMarker : obj);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}
if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}
handles.finish(passHandle);
//重点:这里的意思就是:如果有写readResolve方法,就调用readResovle方法
if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
{
//反射调用ReadResolve方法
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
handles.setObject(passHandle, obj = rep);
}
}
return obj;
}
反射破坏单例
HungrySingleton singleton = HungrySingleton.getInstance();
Class<HungrySingleton> clazz = HungrySingleton.class;
Constructor<HungrySingleton> declaredConstructor = clazz.getDeclaredConstructor();
//主要就是反射可以破坏封装性,因此破坏单例也是允许的
declaredConstructor.setAccessible(true);
HungrySingleton newInstance = declaredConstructor.newInstance();
System.out.println(singleton);
System.out.println(newInstance);
System.out.println(singleton==newInstance);
网友评论