让我们来破坏单例模式

java中的单例模式经常会被问及作为单例的安全性,是否真正的能够实现实例的唯一性。正常情况下我们考虑是可以实现实例的唯一性的,如下单例:
public  class Singleton {
     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());
    }
}
此时程序运行结果输出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);
    }
}
此时程序运行结果输出 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);
    }
}
此时程序返回true readResolve 方法使得在反序列化的过程中返回单例中的INSTANCE,而不是生成新的实例。 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值