用私有构造器或者枚举类型强化Singleton
参考Effective Java第三版 Joshua J. Bloch
参与编写JDK的大佬,上次看Collections的源码时看见了他的名字,然后翻了翻书,竟然就是他写的!
1.常见的一种:
public class Singleton {
private static final Singleton INSTANCE=new Singleton();
private Singleton(){
//如果没有判断,可以通过反射使用构造函数创建对象,然后就不是单例了
if (INSTANCE!=null){
//throw Exception
}
}
public static Singleton getInstance(){
return INSTANCE;
}
public void doSomething(){
//...
}
}
通过反射:可以看到singleton的两个实例不是同一个。
class Main {
public static void main(String[] args) {
testSingleton();
}
private static void testSingleton() {
Singleton s1 = Singleton.getInstance();
Class<Singleton> clazz = Singleton.class;
try {
Constructor<Singleton> constructor = clazz.getDeclaredConstructor(new Class[]{});
constructor.setAccessible(true);
Singleton s2 = constructor.newInstance(new Class[]{});
System.out.println(s1 == s2);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
2.用枚举:推荐的方法
优点:引用Effective Java的话:简洁,无偿的提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。单元素的枚举类常是实现Singleton的最佳方法。如果Singleton必须扩展一个超类,而不是扩展Enum时,不适宜使用这个方法。
public enum EnumSingleton {
INSTANCE;
public void doSomething(){
//...
}
}
按照第一个测试的时候会报错的。
3.序列化
序列化有个问题就是,反序列化时会创建一个新的实例,破坏单例,下面让原来那个类实现Serializable接口。
public class Singleton implements Serializable {
private static final Singleton INSTANCE=new Singleton();
private Singleton(){
if (INSTANCE!=null){
try {
throw new Exception("INSTANCE已存在!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static Singleton getInstance(){
return INSTANCE;
}
public void doSomething(){
//...
}
}
测试一下:Effective Java的第9条 使用try-with-resources优于try-finally,关闭资源的时候。
private static void testSerializableSingleton() {
File file=new File("singleton.out");
try(ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(file));
ObjectInputStream in=new ObjectInputStream(new FileInputStream(file))){
out.writeObject(Singleton.getInstance());
Singleton singleton= (Singleton) in.readObject();
System.out.println(singleton == Singleton.getInstance());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
打印的结果是false,说明序列化破化了单例,因为反序列化是反射调用了无参构造函数。
解决方法:在类里加入这个方法,详见Effective Java第89条
private Object readResolve() {
return INSTANCE;
}
然后结果就是true了。
不当之处,请指正,谢谢。
用私有构造器或者枚举类型强化Singleton的更多相关文章
- 《Effective Java》-——用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类.Singleton通常被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统.使类成为Singleton会使它的客户端测试变得十分困难,因为无法给Si ...
- 《effective java》读书札记第三条用私有构造器或者枚举类型强化Singleton属性
Singleton指只被实例化一次的类.一般用来搞那些创建很耗资源或者要求系统中只能有一个实例的类. 这个很经常使用.记得曾经实习面试的时候就有这个面试题. 一般採用的方法是将构造器私有化,然后提供一 ...
- Effective Java 之 --- 用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类,通常用来代表那些本质上唯一的系统组件,实现Singleton有三种方法: 1)公有静态成员是个final域,享有特权的用户可以调用AccessibleObje ...
- 【读书笔记 - Effective Java】03. 用私有构造器或者枚举类型强化Singleton属性
实现Singleton(代表本质上唯一的系统组件)的三种方法: 1. 保持私有构造器,导出公有的静态成员,客户端访问该类的唯一实例. 2. 保持私有构造器,公有的成员是静态工厂方法. 3. 单元素的枚 ...
- 第3项:用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类 [Gamma95].Singleton通常代表无状态的对象,例如函数(第24项)或者本质上唯一的系统组件.使类称为Singleton会使它的客户端测试变得 ...
- 用私有构造器或者枚举类型强化Singleton属性
1.Singleton指仅仅被实例化一次的类.Singleton通常被用来代表那些本质上唯一的系统组件,如窗口管理器或者文件系统.使类称为Singleton会使它的客户端调试变的十分困难,因为无法给S ...
- 用私有构造器或枚举类型强化Singleton
Singleton指只有一个实例的类,只能被创建一次. 在Java1.5之前实现Singleton有两种方式,都是将构造器设为private并导出公有的静态成员实例. 第一种方式将公有的静态成员实例设 ...
- 创建和销毁对象——用私有构造器或者枚举类型强化Singleton属性
参考资料:<Effective Java>.<Java核心技术 卷1>.https://www.cnblogs.com/zhaosq/p/10135362.html 基础回顾 ...
- 用私有构造器或者枚举类型强化SingleTon(单例)属性
单例(singleton)就是一个只实例化一次的类.使类成为单例可能会使它的测试变得困难,因为除非它实现了作为其类型的接口,否则不可能用模拟实现来代替这个单例.下面是几种实现单例的方法: 1.共有静态 ...
- 第3条:用私有构造器或者枚举类型强化Singleton属性
Singleton是指仅仅被实例化一次的类.通过被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统. 在http://www.cnblogs.com/13jhzeng/p/5256424. ...
随机推荐
- POJ2243 Knight Moves —— A*算法
题目链接:http://poj.org/problem?id=2243 Knight Moves Time Limit: 1000MS Memory Limit: 65536K Total Sub ...
- wukong引擎源码分析之索引——part 3 文档评分 无非就是将docid对应的fields信息存储起来,为搜索结果rank评分用
之前的文章分析过,接受索引请求处理的代码在segmenter_worker.go里: func (engine *Engine) segmenterWorker() { for { request : ...
- receive和process的过程
(一) receive最终在fuse_kern_chan.c中的fuse_kern_chan_receive函数实现,使用系统调用读取 res = read(fuse_chan_fd(ch), buf ...
- Android隐藏Activity和图标
今天发现4.0以后如果不写Activity只写BroadcastReceiver的话,这个广播接收器是不能运行的.经过查询,好像是HoneyComb之后添加了安全机制,规定必须运行一次Activity ...
- POJ2142:The Balance (欧几里得+不等式)
Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. F ...
- 使用masonry手写约束
在iOS开发过程中,手写contraints是非常痛苦的一件事情,往往那么一丢丢功能要写大量的代码,非常容易发生错误,并且非常不方便调试.所以只有在不得以的情况下才采用手工方式写contraints, ...
- macbook pro上安装虚拟机
第一步:下载MacHunter的app应用商店 第二步:在MacHunter内下载Parallels Desktop虚拟机 第三步:如果在这个商店下载不下来,在网络资源上直接下载Parallels D ...
- python中为什么需要使用“if __name__ == '__main__'”语句
首先用最简洁的语言来说明一下 if __name__ == '__main__': 的作用:防止在被其他文件导入时显示多余的程序主体部分. 先举个例子,如果不用 if __name__ == '__m ...
- Linux和windows下执行sql脚本文件
利用 sqlplus 登录数据库之后 键入: @/全路径/文件名 即可执行*.sql 文件 例 假设有一个 test.sql 文件 所在路径是/home/oracle/ ...
- Python网络爬虫之BeautifulSoup模块
一.介绍: Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮 ...