用私有构造器或者枚举类型强化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. ...
随机推荐
- 为了cider,尝试emacs的坑
https://github.com/clojure-emacs/cider http://clojure-doc.org/articles/tutorials/emacs.html emacs通过b ...
- react native camera
最近在尝试用react native camera iOS版本很方便就调试通过了,react的试用非常方便 android版本要单独试用fork的 屏蔽了lint的报错后也可以调试通过 参考这篇文章填 ...
- POJ1077 Eight —— 正向BFS
主页面:http://www.cnblogs.com/DOLFAMINGO/p/7538588.html 代码一:以数组充当队列,利用结构体中的pre追溯上一个状态在数组(队列)中的下标: #incl ...
- javascript XMLHttpRequest 对象的open() 方法参数说明
下文是从w3c上摘录下来的,其中参数 method 说明的很简短,不是很理解,所以又找了些资料作为补充.文中带括号部分. XMLHttpRequest.open() 初始化 HTTP 请求参数 语法o ...
- JavaScript正则表达式API
1. [代码][JavaScript]代码 参考自<Core JavaScript Reference 1.5> JavaScript正则表达式有两种写法(随便哪种,看个人习惯): ...
- wireshark分析ssl协议
1.什么是ssl SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种 ...
- AndroidStudio修改主题外观和字体大小
修改主题外观 File --> Settings --> Appearance & Behavior --> Appearance 右边 Theme 修改编辑器的字体大小 F ...
- API接口文档的撰写
接口文档: 要写:接口简介.请求参数.返回结果.注意事项. 下面以“喜马拉雅的 ‘圈子’ ”为例子: 接口一 (1)接口简介 http://ipservice.mogujie.com/ipservic ...
- 库&框架-----CDN网络引用总结
百度jquery引用地址 http://apps.bdimg.com/libs/jquery/1.6.4/jquery.js http://apps.bdimg.com/libs/jquery/1.6 ...
- Table View Programming Guide for iOS---(七)---Managing Selections
Managing Selections 管理选择 When users tap a row of a table view, usually something happens as a result ...