天天看点

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

Singleton指仅仅被实例化一次的类。一般用来搞那些创建非常耗资源或者要求系统中只能有一个实例的类。这个非常常用。记得以前实习面试的时候就有这个面试题。一般采用的方法是将构造器私有化,然后提供一个static变量,再提供一个static的public方法用来返回static实例:

//Singleton with static factory
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() {}
public static Elvis getInstance(){
return INSTANCE;
}
public void leaveTheBuilding(){}
}
           

这个是单例工厂方法模式中的饿汉模式,还有一种懒汉模式。就是晚点实例化。就不写了 要提醒一点的是:享有特权的 客户端可以通过反射机制调用私有构造器。也就是平时说的暴力反射。具体可以参考我的另一篇文章: java暴力反射。如果需要抵御这种攻击,可以修改构造器,让它在被要求创建第二个实例的时候抛出异常。 除了工厂方法还有一种是公有域方法:

public class Elvis2 {

public static final Elvis2 INSTANCE = new Elvis2();
private Elvis2(){}
public void leaveTheBuilding(){}
}
           
这种方法的优点就是清晰,明了。缺点就是死板,性能不行。工厂方法优点就是灵活。 缺点就是可以很容易被修改,比如改成为每个调用该方法的线程返回一个唯一的实例。另外这两种方法使这个类变成是可序列化的比较麻烦。。。。所以讲第三种方法:
           
public enum Elivis3 {
INSTANCE;
public void leaveTheBuilding(){}
}
           

这个方法在功能上与公有域方法相近,但是它更加简洁。无偿地提供了序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。虽然这种方法还没有广泛采用,但是但元素的枚举类型已经成为实现Singletong的最佳方法!