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属性的更多相关文章

  1. 《effective java》读书札记第三条用私有构造器或者枚举类型强化Singleton属性

    Singleton指只被实例化一次的类.一般用来搞那些创建很耗资源或者要求系统中只能有一个实例的类. 这个很经常使用.记得曾经实习面试的时候就有这个面试题. 一般採用的方法是将构造器私有化,然后提供一 ...

  2. Effective Java 之 --- 用私有构造器或者枚举类型强化Singleton属性

    Singleton指仅仅被实例化一次的类,通常用来代表那些本质上唯一的系统组件,实现Singleton有三种方法: 1)公有静态成员是个final域,享有特权的用户可以调用AccessibleObje ...

  3. 【读书笔记 - Effective Java】03. 用私有构造器或者枚举类型强化Singleton属性

    实现Singleton(代表本质上唯一的系统组件)的三种方法: 1. 保持私有构造器,导出公有的静态成员,客户端访问该类的唯一实例. 2. 保持私有构造器,公有的成员是静态工厂方法. 3. 单元素的枚 ...

  4. 第3项:用私有构造器或者枚举类型强化Singleton属性

      Singleton指仅仅被实例化一次的类 [Gamma95].Singleton通常代表无状态的对象,例如函数(第24项)或者本质上唯一的系统组件.使类称为Singleton会使它的客户端测试变得 ...

  5. 用私有构造器或者枚举类型强化Singleton属性

    1.Singleton指仅仅被实例化一次的类.Singleton通常被用来代表那些本质上唯一的系统组件,如窗口管理器或者文件系统.使类称为Singleton会使它的客户端调试变的十分困难,因为无法给S ...

  6. 创建和销毁对象——用私有构造器或者枚举类型强化Singleton属性

    参考资料:<Effective Java>.<Java核心技术 卷1>.https://www.cnblogs.com/zhaosq/p/10135362.html 基础回顾 ...

  7. 第3条:用私有构造器或者枚举类型强化Singleton属性

    Singleton是指仅仅被实例化一次的类.通过被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统. 在http://www.cnblogs.com/13jhzeng/p/5256424. ...

  8. 第三条:用私有构造器或者枚举类型强化Singleton属性

    1.使用单元素的枚举类型 public enum Singleton implements Serializable { INSTANCE; private String field; public ...

  9. 用私有构造器或枚举类型强化Singleton

    Singleton指只有一个实例的类,只能被创建一次. 在Java1.5之前实现Singleton有两种方式,都是将构造器设为private并导出公有的静态成员实例. 第一种方式将公有的静态成员实例设 ...

随机推荐

  1. ajax的跨域请求问题:减少options请求

    服务器端在Response Headers里添加字段Access-Control-Max-Age: 86400 , "Access-Control-Max-Age"表明在86400 ...

  2. 道量化交易程序猿(25)--Cointrader之MarketData市场数据实体(12)

    转载注明出处:http://blog.csdn.net/minimicall.http://cloudtrade.top/ 前面一节我们说到了远端事件.当中.市场数据就属于远端事件.市场数据有什么?我 ...

  3. eclipes中配置javadoc文档

  4. 在MVC项目中分页使用MvcPager插件

    参考网站  http://www.webdiyer.com/mvcpager/demos/ 这个插件非常简单易用,如果想快速使用 可以参考我这篇文章,其实参考网站也是非常简单的 首先选择你的web项目 ...

  5. silverlight,WPF动画终极攻略之阳光灿烂篇(Blend 4开发)

    原文:silverlight,WPF动画终极攻略之阳光灿烂篇(Blend 4开发) 前面我们画了一只会飞动的小鸟,今天我们在目标是一个会发光的太阳.本章节的动画虽然简单,但是实现的效果可是一点也不打折 ...

  6. Python 辨异 —— __init__ 与 __new__

    __init__ 更多的作用是初始化属性,__new__ 进行的是创建对象,显然 __new__ 要早于 __init__ 发生. 考虑一个继承自 tuple 的类,显然在 __init__ 无法对其 ...

  7. PYC文件简介

    PYC文件简介¶ 不说废话,这里说的pyc文件就是 Python 程序编译后得到的字节码文件 (py->pyc). 基本格式¶ pyc文件一般由3个部分组成: 最开始4个字节是一个Maigc i ...

  8. ASP.NET Core 用户注册 - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 用户注册 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 用户注册 上一章节我们终于迁移完了 Identity 的数据,也创建 ...

  9. Oltu在Jersey框架上实现oauth2.0授权模块

    oltu是一个开源的oauth2.0协议的实现,本人在此开源项目的基础上进行修改,实现一个自定义的oauth2.0模块. 关于oltu的使用大家可以看这里:http://oltu.apache.org ...

  10. ZOJ 3726 RMQ + 二分法

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5072 区域赛真干的话题 通过率最高的一个问题 不到一半认为这OK  然后WA果 ...