第二天和第三天是周末,继续阅读《Effective java》,周末两天看到了第十条,没时间详细记录阅读体会了,先把学习内容记录一下,等有时间把阅读体会补上。
第2条:使用私有构造函数强化s i n g l e t o n属性
singleton通常有两种方法:
1)把构造函数私有化,然后提供一个公有的静态final成员以供访问
public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } ... // Remainder omitted }
2)私有化构造函数,提供一个工友的静态工厂方法public class Elvis {
private static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } public static Elvis getInstance() { return INSTANCE; } }
第一种方法的主要好处:
从类的成员声明可以很容易看出这是一个singleton,在性能上也可能稍占优,但是第二种方法中,一个优秀的JVM实现应该能够通过将静态工厂方法的调用内联化(inlining),来消除这种差别。
第二种方法主要好处:
提供了灵活性,在不改变API的情况下,允许我们把类做成singleton或者不做成singleton。静态工厂方法返回该类的唯一实例,但是想要修改也很容易,比如说,为每一个调用该方法的线程返回一个唯一的实例。
总而言之,如果你能确定该类永远是一个singleton,那么第一种方法不错,如果你希望有一点余地,那么可以使用第二种方法。
如果你要使得一个singleton的类变为可序列化,那么仅仅是在声明中加上implements serializable是不够的。为了维护singleton性,还必须提供一个readResolve方法,否则,一个序列化的实例在每次反序列化的时候,都会导致创建一个新的实例,上面的例子中就会出现这种情况。为了防止这种情形的发生,我们需要在Elvis类中加上readResolve方法:
private Object readResolve() throws ObjectStreamException { return INSTANCE; }
第3条:通过私有构造函数强化不可实例化的能力
有点时候我们可能会编写一些只有静态方法或者静态域的类,例如java.lang.Math等,这些工具类不希望被实例化因为没有任何意义。但是如果缺省显示的构造函数,那么编译器会自动提供一个无参的公有构造函数。
企图通过将一个类做成抽象类来强制该类不可实例化是行不通的,因为该类可以被子类化,并且该子类也可以被实例化。而且这种做法会误导用户,以为这种类是专门为了继承而设计的。所以我们有一种简单的做法,就是提供一个显示的私有的构造函数,那么就它就不可被实例化了。
这么做也有一个副作用,那就是它不能被子类化。因为所有的构造函数都需要调用一个可访问的父类构造函数,无论是显式的还是隐式的调用,这种情况下,子类就没有可访问的构造函数来调用了。