ITMISS
根据用途,有几个“正确”的答案。从java5开始,最好的方法是使用枚举:public enum Foo {
INSTANCE;}前java5,最简单的情况是:public final class Foo {
private static final Foo INSTANCE = new Foo();
private Foo() {
if (INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
}
public static Foo getInstance() {
return INSTANCE;
}
public Object clone() throws CloneNotSupportedException{
throw new CloneNotSupportedException("Cannot clone instance of this class");
}}我们来看看代码吧。首先,你希望课程是最终的。在这种情况下,我使用了final关键字让用户知道它是最终的。然后,您需要将构造函数设置为私有,以防止用户创建自己的Foo。从构造函数中抛出异常会阻止用户使用反射来创建第二个Foo。然后创建一个private static final Foo字段来保存唯一的实例,并创建一个public static Foo getInstance()返回它的方法。Java规范确保仅在首次使用类时调用构造函数。当你有一个非常大的对象或繁重的构造代码并且还有其他可访问的静态方法或字段可能在需要实例之前使用时,那么你只需要使用延迟初始化。您可以使用a private static class来加载实例。然后代码看起来像:public final class Foo {
private static class FooLoader {
private static final Foo INSTANCE = new Foo();
}
private Foo() {
if (FooLoader.INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
}
public static Foo getInstance() {
return FooLoader.INSTANCE;
}}由于该行private static final Foo INSTANCE = new Foo();仅在实际使用类FooLoader时执行,因此它负责延迟实例化,并且保证是线程安全的。当您还希望能够序列化对象时,需要确保反序列化不会创建副本。public final class Foo implements Serializable {
private static final long serialVersionUID = 1L;
private static class FooLoader {
private static final Foo INSTANCE = new Foo();
}
private Foo() {
if (FooLoader.INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
}
public static Foo getInstance() {
return FooLoader.INSTANCE;
}
@SuppressWarnings("unused")
private Foo readResolve() {
return FooLoader.INSTANCE;
}}该方法readResolve()将确保将返回唯一的实例,即使该对象在上一次运行的程序中被序列化也是如此。