singleton是指这样的类,它只能实例化一次。singleton通常被用来代表那些本质上具有唯一性的系统组件,比如视频显示或者文件系统。
实现singleton有两种方法。这两种方法都要把构造函数保持为私有的,并且提供一个静态成员,以便允许客户能够访问该类唯一的实例:在第一种方法中,公有静态成员是一个final域:
//Singleton with final field
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
...
}
... // Remainder omitted
}
私有构造函数仅被调用一次,用来实例化公有的静态final域Elvis.INSTANCE,由于缺少公有的或者受保护的构造函数Elvis,所以保证了Elvis的全局唯一性:一旦Elvis类被实例化之后,只有一个Elvis实例存在----不多也不少。客户的任何行为都不会改变这一点。
第二种方法提供了一个公有的静态工厂方法,而不是公有的静态final域:
public class Elvis {
private staitc final Elvis INSTANCE = new Elvis();
private Elvis() {
...
}
public static Elvis getInstance() {
return INSTANCE;
}
.... //Remainder omitted
}
所有对于静态方法Elvis.getInstance的调用,都会返回同一个对象引用,所以,不会有别的Elvis实例被创建。
第一种方法的主要好处在于,组成类的成员的声明很清楚地表明了这个类是一个singleton:公有的静态域是final的,所以该域总是包含相同的对象引用。第一种方法可能在性能上稍微领先,但是在第二种方法中,一个优秀的JVM实现应该能够通过将静态工厂方法的调用内联化,来消除这种差别。
第二种方法的主要好处在于,它提供了灵活性:在不改变API的前提下,允许我们改变想法,把该类做成singleton,或者不做成singleton,singleton的静态工厂方法返回该类的唯一实例,但是它也很容易被修改,比如说,为每个调用该方法的线程返回一个唯一的实例。
总而言之,如果你确信该类将永远是一个singleton,那么使用第一种方法是有意义的。如果希望保留一点余地,那么请使用第二种方法。
为了使一个singleton类变成可序列化的(serializable),仅仅在声明中加上“implements Serializable”是不够的,为了维护singleton性,你必须也要提供一个readResolve方法:
private Object readResolve() throws ObjectStreamException {
/**
* Return the one true Elvis and let the grabage collector
* take care of the Elvis impersonator
*
return INSTANCE;
}