如果你序列化一个单例类,然后两次重构它,那么你就会得到那个单例类的两个实例,除非你实现readResolve()方法,像下面这样:
例1 一个可序列化的单例类
Java代码
import
org.apache.log4j.Logger;
public class Singleton implements java.io.Serializable
{
public static Singleton
INSTANCE = new
Singleton();
protected Singleton()
{
// Exists only to thwart
instantiation.
}
private Object readResolve()
{
return
INSTANCE;
}
}
上面的单例类实现从readResolve()方法中返回一个唯一的实例;这样无论Singleton类何时被重构,它都只会返回那个相同的单例类实例。
例2测试了例1 的单例类
例2 测试一个可序列化的单例类
Java代码
import
java.io.*;
import
org.apache.log4j.Logger;
import
junit.framework.Assert;
import
junit.framework.TestCase;
public class SingletonTest extends TestCase
{
private Singleton sone = null,
stwo =
null;
private static Logger logger =
Logger.getRootLogger();
public SingletonTest(String
name) {
super(name);
}
public void setUp()
{
sone =
Singleton.INSTANCE;
stwo =
Singleton.INSTANCE;
}
public void
testSerialize()
{
logger.info("testing singleton
serialization...");
writeSingleton();
Singleton s1 =
readSingleton();
Singleton s2 =
readSingleton();
Assert.assertEquals(true, s1 ==
s2);[/b]
}
private void
writeSingleton()
{
try {
FileOutputStream fos = new
FileOutputStream("serializedSingleton");
ObjectOutputStream oos = new
ObjectOutputStream(fos);
Singleton s =
Singleton.INSTANCE;
oos.writeObject(Singleton.INSTANCE);
oos.flush();
}catch(NotSerializableException se)
{
logger.fatal("Not Serializable Exception: " +
se.getMessage());
}catch(IOException iox)
{
logger.fatal("IO Exception: " +
iox.getMessage());
}
}
private Singleton
readSingleton()
{
Singleton s =
null;
try {
FileInputStream fis = new
FileInputStream("serializedSingleton");
ObjectInputStream ois = new
ObjectInputStream(fis);
s =
(Singleton)ois.readObject();
}catch(ClassNotFoundException cnf)
{
logger.fatal("Class Not Found Exception: " +
cnf.getMessage());
}catch(NotSerializableException se)
{
logger.fatal("Not Serializable Exception: " +
se.getMessage());
}catch(IOException iox)
{
logger.fatal("IO Exception: " +
iox.getMessage());
}
return
s;
}
public void
testUnique()
{
logger.info("testing singleton
uniqueness...");
Singleton another = new
Singleton();
logger.info("checking singletons for
equality");
Assert.assertEquals(true, sone ==
stwo);
}
}
前面这个测试案例序列化例1
中的单例类,并且两次重构它。然后这个测试案例检查看是否被重构的单例类实例是同一个对象。下面是测试案例的输出:
Java代码
Buildfile:
build.xml
init:
[echo] Build 20030422 (22-04-2003
11:32)
compile:
run-test-text:
[java] .INFO main: testing singleton
serialization...
[java] .INFO main: testing singleton
uniqueness...
[java] INFO main: checking singletons for
equality
[java] Time:
0.1
[java] OK (2
tests)
单例模式结束语
单例模式简单却容易让人迷惑,特别是对于Java的开发者来说。在这篇文章中,作者演示了Java开发者在顾及多线程、类载入器和序列化情况如何实现单例模式。作者也展示了你怎样才能实现一个单例类的注册表,以便能够在运行期指定单例类。