单例:只能被实例化一次的类。用来表示那些本质上唯一的系统组件。
单例的缺点
如果单例没有实现接口,则无法用模拟实现替换,所以很难测试单例类。
JDK5之前实现单例的两种方法
都要把构造函数私有化,并导出公有的静态成员,以便允许客户端能够访问该类的唯一实例。
JDK5之前实现单例的两种方法——公有域方法
第一种方法中,公有静态成员是个final
域:
享有特权的客户端可以借助
AccessibleObject.setAccessible
方法,通过反射机制调用私有构造函数。如果需要抵御这种攻击,可以修改构造函数,让它在被要求创建第二个实例的时候抛出异常。
JDK5之前实现单例的两种方法——静态工厂方法
第二种方法,公有的成员是个静态工厂方法。
公有域方法与静态工厂方法的对比
公有域方法的类成员的声明很清楚地表明了这个类是一个单例:公有的静态域都是final
,所以该域将总是包含相同的对象引用。
公有域方法在性能上不再有任何优势:现代的JVM几乎都能够将静态工厂方法的调用内联化。
工厂方法的优势:
灵活性——在不改变API的前提下,可以改变该类为非单例。工厂方法可以返回该类的唯一实例,但是可以修改为每个线程返回一个唯一的实例。
与泛型相关。
公有域方法的优势
公有域方法比较简单。
JDK5之后实现单例的最好实践——单例序列化
implements Serializable
必须声明所有实例域都是瞬时的,并提供一个readResolve
方法。否则每次反序列化时都会创建一个新的实例。
包含单个元素的枚举类型
跟公有域方法类似,但是更简洁,并无偿提供了序列化机制,绝对防止多次实例化。
单元素的枚举类型已经成为实现单例的最佳方法。
网友评论