第二章 创建和销毁对象
第三条 用私有构造器或者枚举类型强化Singleton属性
Singleton是指仅仅被实例化一次的类(也就是单例模式)。
需要满足:
- 只能有一个实例。
- 必须自己创建自己的唯一实例(构造方法私有)。
- 必须给所有其他对象提供这一实例。
一 实现Singleton两种常见方法
1 公有的不可变静态成员
一个孙悟空单例类:
(原文是Elvis即猫王,个人对猫王不熟悉,所以这里就用孙悟空代替好了)
/*孙悟空类*/
public class WuKong {
//公有的静态不可变域来提供实例
public static final WuKong INSTANCE = new WuKong();
//私有的构造方法仅被调用一次
private WuKong() {
}
}
优点:比较简单
2 公有的静态工厂方法
/*孙悟空类*/
public class WuKong {
//私有的静态不可变域
private static final WuKong INSTANCE = new WuKong();
//私有的构造方法仅被调用一次
private WuKong() {
}
//公有的静态工厂方法返回实例
public static WuKong getInstance() {
return INSTANCE;
}
}
优点:
易于取消Singleton
可以编写泛型Singleton工厂(详见第30条)
可以通过方法引用作为提供者(不太懂)
3 注意反射攻击
这两种方法需要注意的是:可以借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。如果需要抵御这种攻击,可以修改构造器,让它在被要求创建第二个实例的时候抛出异常。
4 序列化问题
这两种方法如果只是implements Serializable是不够的,每次反序列化一个序列化的实例时,都会创建一个新的实例(六耳猕猴?)。为了防止这种情况,要在WuKong类中加入readResolve方法:
private Object readResolve(){
return INSTANCE;
}
这样就可以保证反序列化时也同时是singleton了。(具体原理不是很清楚,可以看 这个帖子 的解释)
二 实现Singleton第三种方法
1 实例
声明一个包含单个元素的枚举类型:
/*孙悟空类*/
public enum WuKong {
INSTANCE;
}
2 优点
这种方法十分简洁,且避免了序列化问题和反射攻击。
三 总结
单元素的枚举类型是实现Singleton的最佳方法。
但如果Singleton必须继承一个超类而不是继承一个枚举类时,则不宜使用这个方法(虽然可以声明枚举去实现接口(这里书中没有细说,日后再深入了解一下))。