单例模式

打印 上一主题 下一主题

主题 900|帖子 900|积分 2700

只要是单例模式,构造器一定私有化,即用private修饰。
一.饿汉式单例
  1. package single;
  2. /*
  3.     饿汉式单例
  4. */
  5. public class Hungry {
  6.     //可能会浪费空间
  7.     private byte[] data1 = new byte[1024*1024];
  8.     private byte[] data2 = new byte[1024*1024];
  9.     private byte[] data3 = new byte[1024*1024];
  10.     private byte[] data4 = new byte[1024*1024];
  11.     //构造器私有
  12.     private Hungry() {}
  13.     //实例化私有并且用final修饰
  14.     private final static Hungry HUNGRY = new Hungry();
  15.     public static Hungry getInstance(){
  16.         return HUNGRY;
  17.     }
  18. }
复制代码
二.懒汉式单例
  1. package single;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. //懒汉式单例
  5. public class LazyMan {
  6.     //红绿灯标志位,不让反射获取对象,反射通过构造器来获取对象
  7.     private static boolean blog = false;
  8.     //构造器私有
  9.     private LazyMan() {
  10.         synchronized (LazyMan.class) {
  11.             if (blog == false) {
  12.                 blog = true;
  13.             }else {
  14.                 throw new RuntimeException("不要试图破坏单例");
  15.             }
  16.         }
  17.     }
  18.     //实例化私有
  19.     private volatile static LazyMan lazyMan;
  20.     //双重检验锁模式 懒汉式单例 简称DCL懒汉式
  21.     public static LazyMan getInstance() {
  22.         if (lazyMan == null) {
  23.             synchronized (LazyMan.class) {
  24.                 if (lazyMan == null) {
  25.                     lazyMan = new LazyMan(); // 实例化对象不能够保证原子性,所以加上了volatile关键字,不会产生指令重排
  26.                     /**
  27.                      * 对象的基本创建过程
  28.                      * 1.分配内存空间
  29.                      * 2.执行构造方法,初始化对象
  30.                      *
  31.                      * 123
  32.                      * 132 A线程
  33.                      *     B线程指向A的地址空间,产生了虚无操作,但是lazyMan还没有完成构造
  34.                      */
  35.                 }
  36.             }
  37.         }
  38.         return lazyMan;
  39.     }
  40.     //反射
  41.     public static void main(String[] args) throws Exception {
  42. //        LazyMan instance = LazyMan.getInstance();
  43.         Field blog1 = LazyMan.class.getDeclaredField("blog");
  44.         blog1.setAccessible(true);
  45.         Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
  46.         declaredConstructor.setAccessible(true);
  47.         LazyMan instance = declaredConstructor.newInstance();
  48.         blog1.set(instance,false);
  49.         LazyMan instance1 = declaredConstructor.newInstance();
  50.         blog1.set(instance1,false);
  51.         System.out.println(instance);
  52.         System.out.println(instance1);
  53.     }
  54. }
复制代码
三.静态内部类单例
  1. package single;
  2. //静态内部类
  3. public class Holder {
  4.     private Holder() {
  5.     }
  6.     public static Holder getInstance() {
  7.         return InnerClass.HOLDER;
  8.     }
  9.     public static class InnerClass{
  10.         private final static Holder HOLDER = new Holder();
  11.     }
  12. }
复制代码
四.枚举单例
  1. package single;
  2. import java.lang.reflect.Constructor;
  3. /*
  4.     枚举的class文件中确实有无参构造器,但是通过jad反编译成java文件,
  5.     发现里面有String和int的有参构造,通过无参无法抛出"Cannot reflectively create enum objects"
  6. */
  7. public enum EnumSingle {
  8.     INSTANCE;
  9.     public EnumSingle getInstance() {
  10.         return INSTANCE;
  11.     }
  12. }
  13. class Test{
  14.     public static void main(String[] args) throws Exception {
  15.         EnumSingle instance1 = EnumSingle.INSTANCE;
  16.         Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
  17.         constructor.setAccessible(true);
  18.         EnumSingle instance2 = constructor.newInstance();
  19.         System.out.println(instance1);
  20.         System.out.println(instance2);
  21.     }
  22. }
复制代码

  • 因为反射不能破解枚举单例

  • 并且尝试通过反射来破坏枚举单例,抛出异常却不是上述图片
    Constructor constructor = EnumSingle.class.getDeclaredConstructor(null);参数为null是因为,在.class文件里,我们发现枚举有无参构造

  • 然后我们得到了不一样的异常
    它提示没有这个空参的构造方法
  • 我们进入.class文件,通过命令:javap -p EnumSingle.class 通过反编译得到.java文件的表现形式

  • 既然反编译解决不了这个问题,我们需要通过更专业的工具jad.exe得到他的.java文件,一探究竟
    输入cmd,在dos窗口输入:jad -sjava EnumSingle.class 得到EnumSingle.java文件,打开.java文件发现枚举有一个是有参构造,而不是无参构造

  • 一个类型为String,另外一个为int,然后通过反射来试图破解枚举单例


  • 这次的报错,跟之前通过反射的信息是一致的了


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天津储鑫盛钢材现货供应商

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表