单例(singleton)就是一个只实例化一次的类。使类成为单例可能会使它的测试变得困难,因为除非它实现了作为其类型的接口,否则不可能用模拟实现来代替这个单例。下面是几种实现单例的方法:

1、共有静态成员是final类型

// Singleton with public final field
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
}

私有构造器之后执行一次,实例化Elvis.INSTANCE属性,由于缺少公有(public)的或者受保护(protected)的构造器,所以Elvis一旦被实例化,就只会存在一个Elvis的实例(注:反射是可以实现多次调用私有的构造器,若需要抵御这种攻击,则可以修改私有构造器,让它在被创建第二个实例时,抛出异常,或直接返回第一个实例对象)。

2、公有的成员是一个静态方法。

// Singleton with static factory
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE; }
}

 这个方式可以通过公有静态方法将类改为非单例,但用户代码不需要改变。

为了使利用这其中一种方法实现的SingleTon类变成是可序列化的(Serializable),仅仅在申明上加上“implements Serializable”是不够的。为了维护并保证SingleTon,必须申明所有实例都是瞬时的(transient),并提供一个readResolve方法,否者,每次反序列化一个序列化的实例时,都会创建一个新的实例,比如说,在我们的实例中,会导致“假冒的Elvis”。为了防止这种情况,要在Elvis类中加入下面这个readResolve方法:

参考地址:https://blog.csdn.net/zhushuai1221/article/details/51780895

//1、防止反序列化获取多个对象的漏洞。
//2、无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。
//3、实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。
private Object readResolve(){
return INSTANCE;
}

3、使用枚举实现单例(最佳方式)

/**
* 使用枚举的单例模式
*
*/
public class Elvis{
private Elvis(){}
public static Elvis getInstance(){
return Singleton.INSTANCE.getInstance();
} private enum Singleton{
INSTANCE; private Elvis singleton;
//JVM会保证此方法绝对只调用一次
Singleton(){
singleton = new Elvis();
}
public Elvis getInstance(){
return singleton;
}
}
}

这种方法是在需要的类中编写一个包含单个元素的枚举类型。无偿的提供了序列化机制,绝对防止多次序列化,即使是在面对复杂的序列化或者反射攻击的时候。

  

用私有构造器或者枚举类型强化SingleTon(单例)属性的更多相关文章

  1. 《Effective Java》-——用私有构造器或者枚举类型强化Singleton属性

    Singleton指仅仅被实例化一次的类.Singleton通常被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统.使类成为Singleton会使它的客户端测试变得十分困难,因为无法给Si ...

  2. 《effective java》读书札记第三条用私有构造器或者枚举类型强化Singleton属性

    Singleton指只被实例化一次的类.一般用来搞那些创建很耗资源或者要求系统中只能有一个实例的类. 这个很经常使用.记得曾经实习面试的时候就有这个面试题. 一般採用的方法是将构造器私有化,然后提供一 ...

  3. Effective Java 之 --- 用私有构造器或者枚举类型强化Singleton属性

    Singleton指仅仅被实例化一次的类,通常用来代表那些本质上唯一的系统组件,实现Singleton有三种方法: 1)公有静态成员是个final域,享有特权的用户可以调用AccessibleObje ...

  4. 【读书笔记 - Effective Java】03. 用私有构造器或者枚举类型强化Singleton属性

    实现Singleton(代表本质上唯一的系统组件)的三种方法: 1. 保持私有构造器,导出公有的静态成员,客户端访问该类的唯一实例. 2. 保持私有构造器,公有的成员是静态工厂方法. 3. 单元素的枚 ...

  5. 第3项:用私有构造器或者枚举类型强化Singleton属性

      Singleton指仅仅被实例化一次的类 [Gamma95].Singleton通常代表无状态的对象,例如函数(第24项)或者本质上唯一的系统组件.使类称为Singleton会使它的客户端测试变得 ...

  6. 用私有构造器或者枚举类型强化Singleton属性

    1.Singleton指仅仅被实例化一次的类.Singleton通常被用来代表那些本质上唯一的系统组件,如窗口管理器或者文件系统.使类称为Singleton会使它的客户端调试变的十分困难,因为无法给S ...

  7. 用私有构造器或枚举类型强化Singleton

    Singleton指只有一个实例的类,只能被创建一次. 在Java1.5之前实现Singleton有两种方式,都是将构造器设为private并导出公有的静态成员实例. 第一种方式将公有的静态成员实例设 ...

  8. 创建和销毁对象——用私有构造器或者枚举类型强化Singleton属性

    参考资料:<Effective Java>.<Java核心技术 卷1>.https://www.cnblogs.com/zhaosq/p/10135362.html 基础回顾 ...

  9. 第3条:用私有构造器或者枚举类型强化Singleton属性

    Singleton是指仅仅被实例化一次的类.通过被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统. 在http://www.cnblogs.com/13jhzeng/p/5256424. ...

随机推荐

  1. 外包项目测试工作量评估指南&外包项目测试验收流程

    ## ### 外包项目测试工作量评估指南 1.目的        编写本指导书的目的旨在为我公司进行测试外包服务工作进行指导,帮助项目经理和相关人员编写测试方案.评估工作量.制定测试计划和测试策略等, ...

  2. maven插件之maven-surefire-plugin,junit单元测试报告和sonar测试覆盖率的整合说明

    POM中配置的如下: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId> ...

  3. linux0.11内核源码——用户级线程及内核级线程

    参考资料:哈工大操作系统mooc 用户级线程 1.每个进程执行时会有一套自己的内存映射表,即我们所谓的资源,当执行多进程时切换要切换这套内存映射表,即所谓的资源切换 2.但是如果在这个进程中创建线程, ...

  4. java File类的使用以及一些函数

    package file; import java.io.File; import java.io.IOException; import org.junit.jupiter.api.Test; /* ...

  5. 【Linux】grub引导修复

    将系统盘挂载上并设置开机从光盘启动(U盘也可以) 进入系统安装引导初始界面,然后选择最后一项Troubleshooting 然后选择第二项Rescue a CentOS system进入系统救援模式选 ...

  6. SQL学习记录:定义(一)

    --1.在这里@temp是一个表变量,只有一个批处理中有效,declare @temp table; --2. 如果前面加#就是临时表,可以在tempDB中查看到,它会在最后一个使用它的用户退出后才失 ...

  7. 全国5A级旅游景区已达250家

    至目前,全国5A级旅游景区已达250家,快来数数你去过多少? 全国5A级旅游景区 西藏(+) 拉萨市大昭寺.拉萨布达拉宫景区.日喀则扎什伦布寺景区.林芝巴松措景区 新增1:日喀则扎什伦布寺景区 扎什伦 ...

  8. /proc/interrupts /proc/stat 查看中断信息

    /proc/interrupts列出当前所以系统注册的中断,记录中断号,中断发生次数,中断设备名称 如下图:从左至右:中断号   中断次数  中断设备名称 从上图可知中断号为19的arch_timer ...

  9. python的列表与shell的数组

    python:names=["a","b","c"] shell:names=(a b c)

  10. 【python】 读写文件

    #标准输出 sys.stdout.write() sys.stderr.write() #标准输入 while True : try: line = raw_input().rstrip(); exc ...