单例模式:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法实现,也就是类加载就实例化,单例模式应用场景有很多,比如一个应用有一套窗口化界面,Servlet中只有一个实例,应用很广泛
packagecom.test;public classSingleton {privateSingleton() {}private static final Singleton INSTANCE = newSingleton(); //饿汉模式public staticSingleton getInstance() {returnINSTANCE;
}
}
单例模式基本上是每个java程序员都知道的,effective java第一章讲的是对象创建与销毁,看到单例模式在序列化中会失效时,这个是我之前所不知道的,于是查阅资料,并亲自验证一下,过程很简单,将上面的单例类实现Serializable接口
packagecom.test;importjava.io.Serializable;public class Singleton implementsSerializable{
private static final long serialVersionUID = -6367362518368424353L;privateSingleton() {}private static final Singleton INSTANCE = newSingleton();public staticSingleton getInstance() {returnINSTANCE;
}
}
是时候来验证一下了
packagecom.test;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;public classTest {public static void main(String[] args) throwsFileNotFoundException, IOException, ClassNotFoundException {
Singleton before=Singleton.getInstance();//序列化,将对象写入到文件
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\objectFile"));
oos.writeObject(before);
oos.close();//反序列化,读取文件,还原成对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\objectFile"));
Singleton after=(Singleton) ois.readObject();
ois.close();//验证结果
System.out.println(before ==after);
}
}
输出:false
这说明一旦对象被序列化了,就破坏了单例模式,因为重新读取的对象已经不是之前的对象,它重新生成了一个!
那么问题来了,如何解决单例模式与序列化的矛盾?
effective给出了解决方法,只需添加一个readResolve方法,即
packagecom.test;importjava.io.Serializable;public class Singleton implementsSerializable{
private static final long serialVersionUID = -6367362518368424353L;privateSingleton() {}private static final Singleton INSTANCE = newSingleton();public staticSingleton getInstance() {returnINSTANCE;
}privateObject readResolve() {returnINSTANCE;
}
}
再运行一下之前的测试类,发现结果又变成true了,说明反序列化单例模式没有被破坏!关于其中的原理可以参阅这篇博客 http://www.hollischuang.com/archives/1144
终极解决方法,枚举类!
使用起来极其简单,只需要
packagecom.test;importjava.io.Serializable;public enum Singleton implementsSerializable{
INSTANCE;
}
然后再测试一下
packagecom.test;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;public classTest {public static void main(String[] args) throwsFileNotFoundException, IOException, ClassNotFoundException {
Singleton before=Singleton.INSTANCE;//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\objectFile"));
oos.writeObject(before);
oos.close();//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\objectFile"));
Singleton after=(Singleton) ois.readObject();
ois.close();//验证结果
System.out.println(before ==after);
}
}
输出结果为true