首页 > 基础资料 博客日记
单例模式
2023-08-11 16:50:02基础资料围观200次
文章单例模式分享给大家,欢迎收藏Java资料网,专注分享技术知识
只要是单例模式,构造器一定私有化,即用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<EnumSingle> 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,然后通过反射来试图破解枚举单例
- 这次的报错,跟之前通过反射的信息是一致的了
文章来源:https://www.cnblogs.com/mbkss/p/17623393.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签: