只要是单例模式,构造器一定私有化,即用private修饰。
一.饿汉式单例
- package single;
- /*
- 饿汉式单例
- */
- public class Hungry {
- //可能会浪费空间
- private byte[] data1 = new byte[1024*1024];
- private byte[] data2 = new byte[1024*1024];
- private byte[] data3 = new byte[1024*1024];
- private byte[] data4 = new byte[1024*1024];
- //构造器私有
- 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);
- }
- }
复制代码
- 因为反射不能破解枚举单例

- 并且尝试通过反射来破坏枚举单例,抛出异常却不是上述图片
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,然后通过反射来试图破解枚举单例

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

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