在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;
}
分享到:
相关推荐
NULL 博文链接:https://java--hhf.iteye.com/blog/2171034
下面小编就为大家带来一篇浅谈Python 的枚举 Enum。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
选项Swift软件包,用于更强大的Enum类型。 目录介绍特征安装用法设置一个MappedValueRepresentable枚举使用MappedValueCollectionRepresented 使用MappedEnum类型的可编码枚举在ESet中使用OptionSet中的EnumSet 将...
Enum.doc Enum.docEnum.doc Enum.doc Enum.doc Enum.doc Enum.doc Enum.doc Enum.doc
2. enum与enum class的区别? (为什么需要限定作用域?) 答:枚举作用域是指枚举类型成员名字的作用域,起自其声明之处,终止枚举定义结束之处。enum与class enum区别在于是否限定其作用域。C语言规定,枚举类型...
Enum的用法Enum的用法Enum的用法Enum的用法
常见的enum类型重定义的解决方法,清晰明了。
php-enum, PHP Enum实现灵感来自 SplEnum PHP enum 实现来自 SplEnum 为什么?首先,SplEnum 并不集成到PHP中,你必须单独安装它。使用 enum 而不是类常量提供了以下优点:你可以键入提示: function setAction(Ac
Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类...
主要介绍了浅谈Java中是否直接可以使用enum进行传输,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
用于枚举磁盘设备的 Enumdisk 示例
Java中的Enum的使用与分析
enum测试代码
一个分析 enum 结构分析 源码资源
opc enum 32_64安装包
java enum详细教程。由浅入深,包括基本语法方面..很适合新手学习。/n各位看官。绝对超值。
Laravel开发-enum PHP的枚举实现
简单介绍了DNS和ENUM的原理及在IMS网络中的使用