《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.枚举可以添加任意的方法和 ...
随机推荐
- VR应用评测 - Luna
Luna http://store.steampowered.com/app/605770/Luna/ Steam VR 2017年10月发布 | 开发者:Funomena | 好评率92% 一款制作 ...
- http转换为https
1.下载ssl 证数 百度ssl 证数都有 其中以便宜ssl为例子 注册登陆 选择免费版 可以使用3个月: 申请过程中需要检测该域名是否为本人所有 ,所以邮箱检测或者域名配置 很简单检测就好了: 验证 ...
- ng 点击事件
执行事件获取数据 <div class="shijian"> <p>ng 事件</p> <p><button (click)= ...
- Java 学习笔记之 线程interrupted方法
线程interrupted方法: interrupted()是Thread类的方法,用来测试当前线程是否已经中断. public class InterruptThread extends Threa ...
- 【SQL】 收入支出求盈亏
求项目ID为1000的盈亏 表名为:T 字段:ID P_ID AMOUNT TYPE(1:收入 2:支出) '
- 第三方登录之GitHub篇
第一步,准备工作.获取Client ID和Client Secret 1.自行登陆GitHub官网,点击Setting,如下图: 2.继续,点击Developer settings,如下图: 3.继续 ...
- Spring Cloud 入门系列(一)
前言 Spring Could作为目前最流行基于Java开发的构建微服务的完整框架.发现目前相关系列教程太少,本文是基于官网教程做的一套翻译. 何为Spring Cloud? Spring Cloud ...
- Spring Cloud Alibaba(一) 如何使用nacos服务注册和发现
Nacos介绍 Nacos 致力于帮助您发现.配置和管理微服务.Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现.服务配置.服务元数据及流量管理. Nacos 帮助您更敏捷和容易地构 ...
- DCL语句
DCL语句我们现在默认使用的都是root用户,超级管理员,拥有全部的权限.但是,一个公司里面的数据库服务器上面可能同时运行着很多个项目的数据库.所以,我们应该可以根据不同的项目建立不同的用户,分配不同 ...
- SpringBoot应用入门
一.项目搭建 使用IDEA,点击create new project,然后左边的spring initializr,右边SDK1.8,URL:https://start.spring.io,next ...