天津储鑫盛钢材现货供应商 发表于 2023-8-11 18:32:32

单例模式

只要是单例模式,构造器一定私有化,即用private修饰。
一.饿汉式单例
package single;

/*
    饿汉式单例
*/
public class Hungry {

    //可能会浪费空间
    private byte[] data1 = new byte;
    private byte[] data2 = new byte;
    private byte[] data3 = new byte;
    private byte[] data4 = new byte;

    //构造器私有
    private Hungry() {}

    //实例化私有并且用final修饰
    private final static Hungry HUNGRY = new Hungry();

    public static Hungry getInstance(){
      return HUNGRY;
    }
}二.懒汉式单例
package single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

//懒汉式单例
public class LazyMan {

    //红绿灯标志位,不让反射获取对象,反射通过构造器来获取对象
    private static boolean blog = false;

    //构造器私有
    private LazyMan() {
      synchronized (LazyMan.class) {
            if (blog == false) {
                blog = true;
            }else {
                throw new RuntimeException("不要试图破坏单例");
            }
      }
    }

    //实例化私有
    private volatile static LazyMan lazyMan;

    //双重检验锁模式 懒汉式单例 简称DCL懒汉式
    public static LazyMan getInstance() {
      if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                  lazyMan = new LazyMan(); // 实例化对象不能够保证原子性,所以加上了volatile关键字,不会产生指令重排
                  /**
                     * 对象的基本创建过程
                     * 1.分配内存空间
                     * 2.执行构造方法,初始化对象
                     *
                     * 123
                     * 132 A线程
                     *   B线程指向A的地址空间,产生了虚无操作,但是lazyMan还没有完成构造
                     */
                }
            }
      }
      return lazyMan;
    }

    //反射
    public static void main(String[] args) throws Exception {
//      LazyMan instance = LazyMan.getInstance();
      Field blog1 = LazyMan.class.getDeclaredField("blog");
      blog1.setAccessible(true);
      Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
      declaredConstructor.setAccessible(true);
      LazyMan instance = declaredConstructor.newInstance();
      blog1.set(instance,false);
      LazyMan instance1 = declaredConstructor.newInstance();
      blog1.set(instance1,false);
      System.out.println(instance);
      System.out.println(instance1);
    }
}三.静态内部类单例
package single;

//静态内部类
public class Holder {

    private Holder() {

    }
    public static Holder getInstance() {
      return InnerClass.HOLDER;
    }

    public static class InnerClass{
      private final static Holder HOLDER = new Holder();
    }

}四.枚举单例
package single;

import java.lang.reflect.Constructor;

/*
    枚举的class文件中确实有无参构造器,但是通过jad反编译成java文件,
    发现里面有String和int的有参构造,通过无参无法抛出"Cannot reflectively create enum objects"
*/

public enum EnumSingle {

    INSTANCE;
    public EnumSingle getInstance() {
      return INSTANCE;
    }
}

class Test{

    public static void main(String[] args) throws Exception {
      EnumSingle instance1 = EnumSingle.INSTANCE;
      Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
      constructor.setAccessible(true);
      EnumSingle instance2 = constructor.newInstance();
      System.out.println(instance1);
      System.out.println(instance2);
    }
}

[*]因为反射不能破解枚举单例
https://img2023.cnblogs.com/blog/3251666/202308/3251666-20230811161147648-291524129.png
[*]并且尝试通过反射来破坏枚举单例,抛出异常却不是上述图片
Constructor constructor = EnumSingle.class.getDeclaredConstructor(null);参数为null是因为,在.class文件里,我们发现枚举有无参构造
https://img2023.cnblogs.com/blog/3251666/202308/3251666-20230811161637790-1031284413.png
[*]然后我们得到了不一样的异常
https://img2023.cnblogs.com/blog/3251666/202308/3251666-20230811161840531-1416436085.jpg它提示没有这个空参的构造方法
[*]我们进入.class文件,通过命令:javap -p EnumSingle.class 通过反编译得到.java文件的表现形式
https://img2023.cnblogs.com/blog/3251666/202308/3251666-20230811162330842-971265203.png
[*]既然反编译解决不了这个问题,我们需要通过更专业的工具jad.exe得到他的.java文件,一探究竟
输入cmd,在dos窗口输入:jad -sjava EnumSingle.class 得到EnumSingle.java文件,打开.java文件发现枚举有一个是有参构造,而不是无参构造
https://img2023.cnblogs.com/blog/3251666/202308/3251666-20230811163932589-1453399534.png
[*]一个类型为String,另外一个为int,然后通过反射来试图破解枚举单例
https://img2023.cnblogs.com/blog/3251666/202308/3251666-20230811164109543-729385340.png

[*]这次的报错,跟之前通过反射的信息是一致的了
https://img2023.cnblogs.com/blog/3251666/202308/3251666-20230811164220679-1477767917.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 单例模式