java中的单例模式经常会被问及作为单例的安全性,是否真正的能够实现实例的唯一性。正常情况下我们考虑是可以实现实例的唯一性的,如下单例:
publicclassSingleton{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicSingletongetInstance(){
returnthis.INSTANCE;
}
}
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicSingletongetInstance(){
returnthis.INSTANCE;
}
}
上面的单例类可以返回唯一的实例。
但是我们引入(1)反射机制(2)序列化机制之后就会变得不同
一、反射机制的引入来破坏单例模式
下面是一个单例类,我们通过反射机制生成该类的一个实例。
importjava.lang.reflect.Constructor;
publicclassSingleton{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicSingletongetInstance(){
returnINSTANCE;
}
publicstaticvoidmain(String[]args)throwsException{
//反射机制破坏单例模式
Classclazz=Singleton.class;
Constructorc=clazz.getDeclaredConstructor();
//反射机制使得private方法可以被访问!!!
c.setAccessible(true);
//判断反射生成的对象与单例对象是否相等
System.out.println(Singleton.INSTANCE==c.newInstance());
}
}
publicclassSingleton{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicSingletongetInstance(){
returnINSTANCE;
}
publicstaticvoidmain(String[]args)throwsException{
//反射机制破坏单例模式
Classclazz=Singleton.class;
Constructorc=clazz.getDeclaredConstructor();
//反射机制使得private方法可以被访问!!!
c.setAccessible(true);
//判断反射生成的对象与单例对象是否相等
System.out.println(Singleton.INSTANCE==c.newInstance());
}
}
此时程序运行结果输出false,可以看出反射机制生成了新的对象,因此反射可以破坏单例模式。
二、序列化机制来破坏单例模式
序列化可以实现从字节码生成对象,因此序列化也有可能破坏单例模式
下面给出一个实现了序列化接口Serializable的单例类,看序列化如何生成单例类的一个实例
importjava.io.ByteArrayInputStream;
importjava.io.ByteArrayOutputStream;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
publicclassSingletonimplementsSerializable{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicstaticvoidmain(String[]args)throwsException{
//支持java.io.Serializable的对象都可以写入流中
ByteArrayOutputStreambos=newByteArrayOutputStream();
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(Singleton.INSTANCE);
//根据字节流生成对象
ByteArrayInputStreambis=newByteArrayInputStream(bos.toByteArray());
ObjectInputStreamois=newObjectInputStream(bis);
SingletonnewSingleton=(Singleton)ois.readObject();
System.out.println(newSingleton==Singleton.INSTANCE);
}
}
importjava.io.ByteArrayOutputStream;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
publicclassSingletonimplementsSerializable{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicstaticvoidmain(String[]args)throwsException{
//支持java.io.Serializable的对象都可以写入流中
ByteArrayOutputStreambos=newByteArrayOutputStream();
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(Singleton.INSTANCE);
//根据字节流生成对象
ByteArrayInputStreambis=newByteArrayInputStream(bos.toByteArray());
ObjectInputStreamois=newObjectInputStream(bis);
SingletonnewSingleton=(Singleton)ois.readObject();
System.out.println(newSingleton==Singleton.INSTANCE);
}
}
此时程序运行结果输出false,可以看出序列化机制生成了新的对象,因此反序列化的过程可以破坏单例模式。
不过可以通过引入readResolve方法来阻止反序列化过程中生成新的实例
如下
importjava.io.ByteArrayInputStream;
importjava.io.ByteArrayOutputStream;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
publicclassSingletonimplementsSerializable{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
privateObjectreadResolve(){
returnINSTANCE;
}
publicstaticvoidmain(String[]args)throwsException{
//支持java.io.Serializable的对象都可以写入流中
ByteArrayOutputStreambos=newByteArrayOutputStream();
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(Singleton.INSTANCE);
//根据字节流生成对象
ByteArrayInputStreambis=newByteArrayInputStream(bos.toByteArray());
ObjectInputStreamois=newObjectInputStream(bis);
SingletonnewSingleton=(Singleton)ois.readObject();
System.out.println(newSingleton==Singleton.INSTANCE);
}
}
importjava.io.ByteArrayOutputStream;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
publicclassSingletonimplementsSerializable{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
privateObjectreadResolve(){
returnINSTANCE;
}
publicstaticvoidmain(String[]args)throwsException{
//支持java.io.Serializable的对象都可以写入流中
ByteArrayOutputStreambos=newByteArrayOutputStream();
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(Singleton.INSTANCE);
//根据字节流生成对象
ByteArrayInputStreambis=newByteArrayInputStream(bos.toByteArray());
ObjectInputStreamois=newObjectInputStream(bis);
SingletonnewSingleton=(Singleton)ois.readObject();
System.out.println(newSingleton==Singleton.INSTANCE);
}
}
此时程序返回true,readResolve方法使得在反序列化的过程中返回单例中的INSTANCE,而不是生成新的实例。