《Effective Java》 读书笔记(三) 使用私有构造方法或枚举实现单例类
1.单例类到现在为止算是比较熟悉的一种设计模式了,最开始写单例模式是在C#里面,想要自己实现一个单例类,代码如下:
public class Instance
{
private static readonly Instance instance = new Instance(); public static Instance Instance
{
get { return instance; }
} private Instance() { }
}
嗯,这是一贯的写法。
《Effective Java》开篇是这样写的:
public class Elvis {
public static final Elvis INSTANCE=new Elvis(); private Elvis(){} }
感觉这样写也没什么问题啊。为什么自己在刚接触单例类的时候,没有想过呢,或者是太习惯将属性写成private的了,导致现在看到上面那段代码,都不能第一时间想到这有什么坏处了。
还是得多思考:如果真的上面的Elvis类一样直接将INSTANCE作为public属性传给用户,那么如果后来INSTANCE有别的什么需求,比如每次调用这个对象时,都需要内置生成一个uuid,那么只能改接口,这不符合面向对象设计的开闭原则。
而使用静态工厂方法:
public class Elvis {
private static final Elvis INSTANCE = new Elvis(); public static Elvis getInstance() {
return INSTANCE;
} private Elvis() {
} }
我们只需要在getInstance里面添加一条代码即可,而这对于用户来说,是感觉不到的。
2.通过静态工厂方法创建单例类的另一个好处是这样写能支持JDK 1.8 新特性:Suppiler
3.为了保证单例是真正的单例的(#)最好使用枚举实现单例模式,使用枚举能够防御各种实例化攻击。
(#:)PS:这里感觉得多说一点:
上面的静态工厂方法提供INSTANCE单例类是平时最常使用的一种方法,但是还有很多的实现方式,具体的自行查找吧。
这里我要说的是:其实上面的方法都不能完全保证程序在整个运行的时间都只有一个这个对象。可以查找一下:单例类与序列化,单例类与反射
防卫单例类与序列化的方法在于实现
private Object readResolve(){
return INSTANCE;
}
原理在于如果序列化过程中readResolve返回为空,则使用反射调用私有构造方法重新构造一个对象。
方位反射的方法在于:
反射主要是能够绕过private的权限机制,使得用户能够使用private的构造方法。
因此我们再构造函数里面添加一个判断,如果第二次调用此函数,则抛出异常即可。
明白了序列化攻击和反射攻击以后,就能大概判断哪些方法能够防止这种情况出现,那种方法不能防止。
因此,使用枚举方法是最好的选择。(此处应该有篇博客详细解释一下)
《Effective Java》 读书笔记(三) 使用私有构造方法或枚举实现单例类的更多相关文章
- Effective Java读书笔记——第三章 对于全部对象都通用的方法
第8条:覆盖equals时请遵守通用的约定 设计Object类的目的就是用来覆盖的,它全部的非final方法都是用来被覆盖的(equals.hashcode.clone.finalize)都有通用约定 ...
- [Effective Java 读书笔记] 第二章 创建和销毁对象 第三 四条
第三条 用私有构造器或者枚举类型强化singleton属性 singleton指只能被实例化一次的类,即将构造器设置为私有,使用公有静态成员来实例化,且只实例化一次对象 第四条 通过私有构造器强化不可 ...
- Effective java读书笔记
2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...
- Effective Java读书笔记完结啦
Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...
- Effective Java 读书笔记之一 创建和销毁对象
一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...
- Effective Java 读书笔记(一):使用静态工厂方法代替构造器
这是Effective Java第2章提出的第一条建议: 考虑用静态工厂方法代替构造器 此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文&l ...
- Effective Java读书笔记--创建和销毁对象
1.优先考虑用静态工厂方法代替构造器2.遇到多个构造器参数时要考虑使用构建器Builder解决参数过多,不可变类型.私有构造方法,静态类的构造方法提供必要参数,剩下可选.new xxx.build() ...
- Effective Java 读书笔记(四):泛型
1 不要使用原始类型 (1)术语 术语 例子 参数化类型(Parameterized type) List<String> 实际类型参数(Actual type parameter) St ...
- [Effective Java 读书笔记] 第6章 枚举和注解
第三十条 用enum代替int 总得来说,使用enum有几点好处 1.编译时的类型安全, 2.可以保证就是自己定义的值,不会有月结风险, 3.每个枚举类型有自己的命名空间 4.枚举可以添加任意的方法和 ...
随机推荐
- LAMP模拟搭建wordpress,phpmyadmin环境
1.安装需要的环境,centos7的mysql叫mariadb,所有的配置文件默认就可以 [root@test ~]# yum install httpd php mariadb mariadb-se ...
- Eclipse导入别人项目爆红叉
1.导入项目之前,请确认工作空间编码已设置为utf-8:window->Preferences->General->Wrokspace->Text file encoding- ...
- PHP 上传文件限制
随笔于新浪面试失败: 需要好好补补了 Windows 环境下的修改方法 ================================================================ ...
- linux下安装配置go语言环境
1,golang中国下载go源码 http://www.golangtc.com/download 请对应系统版本号,linux-amd64.tar.gz为64位系统(推荐) ,linux-386 ...
- BT面板安装php报错configure: error: C preprocessor “/lib/cpp” fails sanity check
使用宝塔面板安装扩展时已经显示添加安装成功了,待我刷新浏览器之后没有安装成功.看了一下执行日志. 缺少必要的C++库,如下命令重装解决. yum reinstall glibc-headers gcc ...
- 直通BAT面试题库锦集
01 python面试题(汇总) 02 面向对象 03 网络和并发编程 04 模块 05 设计模式 06 前端 07 Django框架 08 Flask 09 tornado 10 DB
- vue3.0的安装使用
关于旧版本 Vue CLI 的包名称由 vue-cli 改成了 @vue/cli. 如果你已经全局安装了旧版本的 vue-cli (1.x 或 2.x),你需要先通过 npm uninstall vu ...
- python的闭包操作
调用外函数的时候,只是存了闭包函数给flast列表,这个闭包函数并不是一个结果,个人理解而是存的是当前的环境,比如第一次循环当前的环境就是i=0,第二次循环,当前的环境就是i=1,等. 然后,真正的计 ...
- go语言正则表达式
我们前两节课爬取珍爱网的时候,用到了很多正则表达式去匹配城市列表.城市.用户信息,其实除了正则表达式去匹配,还可以利用goquery和xpath第三方库匹配有用信息.而我利用了更优雅的正则表达式匹配. ...
- Spring 注册BeanPostProcessor 源码阅读
回顾上一篇博客中,在AbstractApplicationContext这个抽象类中,Spring使用invokeBeanFactoryPostProcessors(beanFactory);执行Be ...