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》 读书笔记(三) 使用私有构造方法或枚举实现单例类的更多相关文章

  1. Effective Java读书笔记——第三章 对于全部对象都通用的方法

    第8条:覆盖equals时请遵守通用的约定 设计Object类的目的就是用来覆盖的,它全部的非final方法都是用来被覆盖的(equals.hashcode.clone.finalize)都有通用约定 ...

  2. [Effective Java 读书笔记] 第二章 创建和销毁对象 第三 四条

    第三条 用私有构造器或者枚举类型强化singleton属性 singleton指只能被实例化一次的类,即将构造器设置为私有,使用公有静态成员来实例化,且只实例化一次对象 第四条 通过私有构造器强化不可 ...

  3. Effective java读书笔记

    2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...

  4. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  5. Effective Java 读书笔记之一 创建和销毁对象

    一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...

  6. Effective Java 读书笔记(一):使用静态工厂方法代替构造器

    这是Effective Java第2章提出的第一条建议: 考虑用静态工厂方法代替构造器 此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文&l ...

  7. Effective Java读书笔记--创建和销毁对象

    1.优先考虑用静态工厂方法代替构造器2.遇到多个构造器参数时要考虑使用构建器Builder解决参数过多,不可变类型.私有构造方法,静态类的构造方法提供必要参数,剩下可选.new xxx.build() ...

  8. Effective Java 读书笔记(四):泛型

    1 不要使用原始类型 (1)术语 术语 例子 参数化类型(Parameterized type) List<String> 实际类型参数(Actual type parameter) St ...

  9. [Effective Java 读书笔记] 第6章 枚举和注解

    第三十条 用enum代替int 总得来说,使用enum有几点好处 1.编译时的类型安全, 2.可以保证就是自己定义的值,不会有月结风险, 3.每个枚举类型有自己的命名空间 4.枚举可以添加任意的方法和 ...

随机推荐

  1. 实际体验华为云AI : ModelArts

    国庆前看到了博客园官方博客发布的一篇博客: 学AI有奖:博客园&华为云AI有奖训练营开战啦 本着对AI这种火热的话题,以及华为云博客园联名公仔(次要),我决定参与这个活动. 现在华为云开始全面 ...

  2. springboot结合jpa

    idea中新建springboot项目,引入spring-boot-starter-data-jpa依赖 application.yml中配置数据库连接,示例如下: spring: datasourc ...

  3. 2.linux系统基础笔记(延时操作、实时系统中的定时器、事件)

    延时操作 延时操作是操作系统中经常遇到的一种情形.延时的原因很多,有的时候是为了等待外设芯片处理结束,有的时候是为了暂时释放cpu的使用权,有的就是为了希望在一段时间获取资源,如果没法在单位时间内获取 ...

  4. Redis单线程架构以及工作方式

    一.单线程模型 Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程.其中执行命令阶段,由于Redis是单线程来处理命令的,所有每一条到达服务端的每一条到达服务端的命令都不会 ...

  5. Selenium+PhantomJS使用时报错原因

    运行下面代码:'''PhantomJS运用''' from selenium import webdriverimport time # 通过keys模拟键盘from selenium.webdriv ...

  6. Java集合框架,你了解多少?相信你看了这篇汇总一目了然!

    相信大多数的程序员都知道,Dictionary.Vertor.Stack和Properties这些类被用来存储和操作对象组.但是他们缺少一个核心的主题的. 集合框架设计成要满足以下的几个目标 第一条: ...

  7. 玩转ADB命令(ADB命令使用大全)转载

    ADB是什么 Adb的全称为Android Debug Bridge:android调试桥梁,下图为Android官方对adb的介绍:可以看出,Android的初衷是用adb这样的一个工具来协助开发人 ...

  8. conversion function——转换函数

    类型转换函数 与 explicit关键字 1.类型转换函数 在C++中,可以使用构造函数将一个指定类型的数据转换为类的对象,也可以使用类型转换函数 (type conversion function) ...

  9. js仓库。。。

    <script type="text/javascript" src="//ra.revolvermaps.com/0/0/8.js?i=0ln1fndtptz&a ...

  10. Centos 7.2天兔(Lepus 3.8)数据库监控系统部署

    天兔(Lepus 3.8)数据库监控系统部署 转载自:https://blog.csdn.net/m0_38039437/article/details/79613260 一.安装LAMP基础环境 首 ...