序列化与反序列化 :单例

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、为什么推荐使用枚举来实现单例?

简单来说,枚举在被反射创建的时候,源码中会去判断当前类型是否是枚举,如果是,就会直接抛异常。

参考博客:为什么要用枚举实现单例模式(避免反射、序列化问题)_ITKaven的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值