《Effective Java》-——用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类。Singleton通常被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统。使类成为Singleton会使它的客户端测试变得十分困难,因为无法给Singleton替换模拟实现,除非它实现一个充当其类型的接口。
在Java 1.5发行版本之前,实现Singleton有两种方法。
第一种方法,公有静态成员是个final
域:
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... } public void leaveTheBuilding() { ... }
}
第二种方法,公有的成员是个静态工厂方法:
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE } public void leaveTheBuilding() { ... }
}
但要提醒一点:享有特权的客户端可以借助AccessibleObject.setAccessible
方法,通过反射机制调用私有构造器。如果需要抵御这种攻击,可以修改构造器,让它在被要求创建第二个实例的时候创建异常。
特殊说明:
AccessibleObject类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。
对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。
也就是说享有特权的可以破坏单例模式:
public class MainClass { public static void main(String[] args) throws Exception {
// Person person = new Person.Builder("xiaobai","18").sex("男").country("中国").occupation("程序员").build();
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance(); System.out.println(s1 == s2); // 返回 true for(Constructor<?> c : s1.getClass().getDeclaredConstructors()) {
c.setAccessible(true); // AccessibleObject
Singleton s3 = (Singleton)c.newInstance();
System.out.println(s3 == s2);
} }
}
class Singleton { private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
结果:
修改构造器,让它在被要求创建第二个实例的时候创建异常。
class Singleton {
private static int count = 0;
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
if(count == 1)
throw new RuntimeException ("只能初始化一次!");
count++;
}
public static Singleton getInstance() {
return INSTANCE;
}
}
结果:
从Java 1.5发行版本起,实现Singleton还有第三种方法。只需编写一个包含单个元素的枚举类型:
// Enum singleton - the prefered approach
public enum Elvis {
INSTANCE; public void leaveTheBuilding() { ... }
}
这种方法在功能上与公有方法相近,但是它更加简洁,无偿地提供了序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。虽然这种方法还没有广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。
注:
文章的内容大多是《Effective Java》书中第二章 第3条:用私有构造器或者枚举类型强化Singleton属性 的内容,文中红色部分是我对文章的补充。
《Effective Java》-——用私有构造器或者枚举类型强化Singleton属性的更多相关文章
- 《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属性
参考资料:<Effective Java>.<Java核心技术 卷1>.https://www.cnblogs.com/zhaosq/p/10135362.html 基础回顾 ...
- 第3条:用私有构造器或者枚举类型强化Singleton属性
Singleton是指仅仅被实例化一次的类.通过被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统. 在http://www.cnblogs.com/13jhzeng/p/5256424. ...
- 第三条:用私有构造器或者枚举类型强化Singleton属性
1.使用单元素的枚举类型 public enum Singleton implements Serializable { INSTANCE; private String field; public ...
- 用私有构造器或枚举类型强化Singleton
Singleton指只有一个实例的类,只能被创建一次. 在Java1.5之前实现Singleton有两种方式,都是将构造器设为private并导出公有的静态成员实例. 第一种方式将公有的静态成员实例设 ...
随机推荐
- android点击屏幕隐藏小键盘
原文:android点击屏幕隐藏小键盘 fragment 下隐藏点击空白处隐藏小键盘 view.setOnTouchListener(new OnTouchListener() { @Overri ...
- Android中集成支付宝
手机的在线支付,被认为是2012年最看好的功能,我个人认为这也是移动互联网较传统互联网将会大放光彩的一个功能. 人人有手机,人人携带手机,花钱买东西,不再需要取钱付现,不再需要回家上网银,想买什么,扫 ...
- WPF 3D编程介绍
原文:WPF 3D编程介绍 上一篇文章简单的介绍了WPF编程的相关的内容,也推荐了本书.今天要来讲一下在WPF如何开展3D编程. 使用的xmal 和C#开发的时候:需要使用如下的关键要素: 1:摄像机 ...
- Tab选项卡界面(1)
Tab用一个简单的应用程序接口的标签是集中的界面布局文件的同一页上的接口组件不同的标签.并计划将在主类集中的代码文件.这种方法的优点是,文件在项目数不会被添加,但是,假设Tab接口组件更个性化的标签. ...
- qt线程(转)----这篇很专业!
本文档是自己所整理的一份文档,部分是原创,还转贴了网上的一此资料(已经标明了),(难点是多线程的编写),是有源代码的,大家可以作为参考,用到的知识是视频采集,压缩解压(xvid),实时传输(jrtp) ...
- mac_开发机初始化环境
#安装 homebrew 类似 yum ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/ma ...
- Google CFO 辞职信
Google CFO 辞职信 After nearly 7 years as CFO, I will be retiring from Google to spend more time with ...
- 使用FileStream向txt格式的文本文件 "追加" 新内容并读取
原文:使用FileStream向txt格式的文本文件 "追加" 新内容并读取 //得到文件路径. static string filePath = AppDomain.Curren ...
- ios 双指捏合放大缩小图片的例子
图片跟随双指捏合的距离放大或者缩小. 利用-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 实现. touchesMov ...
- MVC EF Model First
1 在Models下新建实体数据模型Model.edmx 2 在Model.edmx中点右键建立各个实体,增加Scalar Property 3 空白处点右键,添加关系,勾选增加外键 4 保存Mode ...