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