单例(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;
}
}
}

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

  

最新文章

  1. css样式让input垂直居中
  2. Windows多线程多任务设计初步(转)
  3. [NHibernate]持久化类(Persistent Classes)
  4. 第13章 .NET应用程序配置
  5. Hive介绍、安装(转)
  6. Java中如何使封装自己的类,建立并使用自己的类库?
  7. synchronized的使用方法
  8. JavaScript 设置、读取Cookie
  9. POJ 3421
  10. 异步加载DOM造成的高度问题造成iScroll不能滚动
  11. windows下virtualenv使用报错
  12. Angular2中的host
  13. TRECT的使用
  14. Oracle在不同的语言环境结果to_date错误的问题
  15. 我的java学习笔记(一)
  16. MySQL学习12 - pymysql模块的使用
  17. P4233 射命丸文的笔记
  18. P2P原理(转)
  19. 采用xtrabackup部署主从同步
  20. 排查bug的步骤

热门文章

  1. ThinkPHP import 类库导入 include PHP文件
  2. Java管道流学习
  3. Eclipse中 Run as --->Maven build 命令详解
  4. IO流 读写文件
  5. GO富集分析 信号通路
  6. u-tools图床便捷生成markdown图片
  7. 解决如何通过循环来使用数据库的值设置jsp的select标签的option值
  8. Linux系统重要文件(三)
  9. 实验1 C语言环境使用和数据类型 运算符 表达式
  10. SQL语句中,除数为0时,相应方法