1、单例类防止反序列化?
class Singleton implements Serializable{
public static Singleton INSTANCE = new Singleton();
private Singleton(){}
private Object readResolve(){
return INSTANCE;
}
}
java.io.ObjectInputStream#readOrdinaryObject:
private Object readOrdinaryObject(boolean unshared) throws IOException {
......
if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
{
// 触发此处可以调用我们写的readResolve方法,所以最终拿到的就是同一个对象。
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
......
return obj;
}
2、单例类如何防止反射?
e1 和 e2是两个不同实例,导致单例存在多个实例。
public class SingleInstance {
private static boolean flag = false;
private TestClass(){
}
private static class SingletonHolder{
private static final SingleInstance INSTANCE = new SingleInstance();
}
public static SingleInstance getInstance() {
return SingletonHolder.INSTANCE;
}
}
public class SingleInstanceHack
{
public static void main(String[] args) Throws Exception
{
Class<?> classType = SingleInstance .class;
Constructor<?> c = classType.getDeclaredConstructor(null);
c.setAccessible(true);
SingleInstance e1 = (SingleInstance )c.newInstance();
SingleInstance e2 = SingleInstance .getInstance();
// e1 和 e2是两个不同实例,导致单例存在多个实例。
System.out.println(e1==e2);
}
}
解决方式:通过标志位来防止单例被反射创建,创建第二个实例的时候,就发生奔溃。
class Singleton {
// 通过标志位来防止单例被反射创建,创建第二个实例的时候,就发生奔溃。
private static boolean flag = false;
private Singleton1(){
synchronized(Singleton.class){
if(!flag){
flag = true;
} else {
throw new RuntimeException("单例模式被侵犯!");
}
}
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
3、当单例类被多个类加载器加载,如何还能保持单例?
利用双亲委派机制,用多个类加载器的父类来加载单例类。
4、为什么推荐使用枚举来实现单例?
简单来说,枚举在被反射创建的时候,源码中会去判断当前类型是否是枚举,如果是,就会直接抛异常。