由于对象反序列化对象,总会生出一个新的实例,这使得原本的singleton对象,一旦实现了Serializable接口,就不能正常工作了,看代码:
public class Singleton implements Serializable {
/**
*
*/
private static final long serialVersionUID = -5902363018159528162L;
private int count = 0;
private static Singleton instance = new Singleton();
static {
System.out.println("static");
instance = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
测试代码:
@Test
public void testSingletonWithSerializable() {
storeSingleton();
Singleton singleton = null;
singleton = restore();
singleton.setCount(10);
Singleton singleton1 = restore();
Assert.assertEquals(10, singleton1.getCount());
}
private Singleton restore() {
Singleton singleton=null;
try {
FileInputStream fis = new FileInputStream("d:\\singleton.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
singleton = (Singleton)ois.readObject();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return singleton;
}
private void storeSingleton() {
Singleton singleton = Singleton.getInstance();
try {
FileOutputStream fos = new FileOutputStream("d:\\singleton.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(singleton);
oos.flush();
oos.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
运行后结果:
写道
junit.framework.AssertionFailedError: expected:<10> but was:<0>
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.failNotEquals(Assert.java:283)
at junit.framework.Assert.assertEquals(Assert.java:64)
at junit.framework.Assert.assertEquals(Assert.java:195)
at junit.framework.Assert.assertEquals(Assert.java:201)
at ully.designpattern.singleton.SingletonTest.testSingletonWithSerializable(SingletonTest.java:32)
显然,第二次读取的singleton对象是新的。
如此,如何解决此问题呢,答案是需要在Singleton类中添加一个回调方法:
private Object readResolve(){
return instance;
}
这其实就相当于做了一个hack,代码在执行ObjectInputStream的readObject()方法时,会先去检查该序列化类是否有readResolve方法,如果有会将object替换成ReadResolve方法返回的对象。
/**
* Invokes the readResolve method of the represented serializable class and
* returns the result. Throws UnsupportedOperationException if this class
* descriptor is not associated with a class, or if the class is
* non-serializable or does not define readResolve.
*/
Object invokeReadResolve(Object obj)
throws IOException, UnsupportedOperationException
{
if (readResolveMethod != null) {
try {
return readResolveMethod.invoke(obj, (Object[]) null);
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ObjectStreamException) {
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
throw new InternalError(); // never reached
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError();
}
} else {
throw new UnsupportedOperationException();
}
}
如此,添加了ReadResolve方法,即可保证每次反序列化的对象均是单例的。