在JDK1.5之前的单例实现方式有两种(懒汉式和饿汉式并无设计上的区别故看做一种),两者同是私有构
造器,导出静态成员变量,以便调用者访问。
第一种
package singleton;
public class Singleton {
//导出全局成员
public final static Singleton INSTANCE = new Singleton();
//私有构造
private Singleton(){}
}
私有构造器只会被调用一次,用于构建Singleton类中的INSTANCE 实例,由于构造器被私有化,并且没
有其他公开的构造器,所有能够保证在app中只会有一个Singleton实例。
真的是我们想的那样只会存在一个么?答案是否定的,可以使用java反射包提供的setAccessible()
方法去掉权限检查即可构造出实例对象
使用反射构造单例对象
final Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
//忽略检查
constructor.setAccessible(false);
//构造对象实例
final Object newInstance = constructor.newInstance();
System.out.println(newInstance == Singleton.INSTANCE); //false
}
现在单例类被反射轻松攻破了吧。
再看第二种基于工厂方法的单例
package singleton;
public class Singleton {
//导出全局成员
private final static Singleton INSTANCE = new Singleton();
//私有构造
private Singleton(){}
public static final Singleton getInstance(){
return INSTANCE;
}
}
该方式与第一种差别并不大,工厂方法的优势在于灵活性,在不改变API的前提下,我们可以修改该类
是否为单例,还是为每一个线程构建一个实例对象。同第一中方式相同也存在反射攻击的可能性,为了
防止反射攻击,需要对私有构造进行改写
package singleton;
import java.lang.reflect.Constructor;
public class Singleton {
//导出全局成员
public final static Singleton INSTANCE = new Singleton();
//私有构造
private Singleton(){
if (null != INSTANCE) {
throw new IllegalArgumentException("不能存在两个实例对象");
}
}
public static void main(String[] args) throws Exception {
final Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
//忽略检查
constructor.setAccessible(false);
//构造对象实例 此时这里回抛出异常
final Object newInstance = constructor.newInstance();
System.out.println(newInstance == Singleton.INSTANCE);
}
}
这样子也可以就可以保证不受反射的攻击啦。
在JDK1.5之后的版本提供了枚举关键字,提供了更加方便的单例创建方式
public enum Singleton {
INSTANCE;
}
三句代码搞定一个单例,并且无偿的提供序列化机制,绝对防止多实例的存在。
以上两种方式如果序列化,仅仅是实现serialiazble接口是不够的,为了维护和保证Singleton请提供
一个方法
public Singleton redResolve(){
return INSTANCE;
}
分享到:
相关推荐
在Java编程中,单例设计模式是一种常见的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这种模式在需要频繁创建和销毁对象,或者对象创建代价较大,且需要全局共享资源时非常有用。在日志工具类的场景...
单例设计模式是软件设计模式中的一种,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。在Java中,单例模式的应用广泛,尤其是在处理系统级服务、配置信息、线程池等需要全局共享的对象时。下面我们将...
scratch少儿编程逻辑思维游戏源码-米克 demo.zip
scratch少儿编程逻辑思维游戏源码-萝卜男孩拯救世界.zip
scratch少儿编程逻辑思维游戏源码-酷忍者.zip
教育科技_微信小程序_二手交易平台_大学校园二手书与物品循环利用公益系统_风华读书人校园二手交易平台_基于C2C模式的校内闲置物品交易系统_支持多校区独立运营的二手书交易平台_包含
全新UI彩虹外链网盘系统源码前后端美化模板整站 模版文件.zip
maoxig_nonebot-plugin-ai-timetable_32152_1745865455265
少儿编程scratch项目源代码文件案例素材-足球顶尖高手.zip
少儿编程scratch项目源代码文件案例素材-作战基地.zip
少儿编程scratch项目源代码文件案例素材-云端之上 1-4名玩家.zip
scratch少儿编程逻辑思维游戏源码-魔幻之塔.zip
scratch少儿编程逻辑思维游戏源码-楼层酷跑.zip
scratch少儿编程逻辑思维游戏源码-圈.zip
少儿编程scratch项目源代码文件案例素材-纸片马里奥自定义战役.zip
少儿编程scratch项目源代码文件案例素材-自由下落.zip
少儿编程scratch项目源代码文件案例素材-阻击蜈蚣.zip
健康监测与疾病预防_脉搏波分析_六轴加速度传感器_生理参数融合_STC12硬件采集_Android数据处理_SpringBoot后端_MySQL数据库_MatlabPython实验
音乐流媒体应用开发_基于JetpackCompose的跨平台开发_网易云音乐风格的多终端音乐播放器_包含手机平板电视手表四端适配的现代化音乐播放应用实现音乐发现播放列表管理个性化推
移动应用开发_Android_Kotlin_Jetpack_开源框架_课程表应用_学生管理_教育信息化_云舒课表_智能课表_课表提醒_成绩查询_主题定制_背景更换_自动静音_校园生