第二天和第三天(第2-3条)

第二天和第三天是周末,继续阅读《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等,这些工具类不希望被实例化因为没有任何意义。但是如果缺省显示的构造函数,那么编译器会自动提供一个无参的公有构造函数。

 

企图通过将一个类做成抽象类来强制该类不可实例化是行不通的,因为该类可以被子类化,并且该子类也可以被实例化。而且这种做法会误导用户,以为这种类是专门为了继承而设计的。所以我们有一种简单的做法,就是提供一个显示的私有的构造函数,那么就它就不可被实例化了。

这么做也有一个副作用,那就是它不能被子类化。因为所有的构造函数都需要调用一个可访问的父类构造函数,无论是显式的还是隐式的调用,这种情况下,子类就没有可访问的构造函数来调用了。

 

你可能感兴趣的:(jvm)