在Java中,使用枚举作为单例模式的最佳方法是什么?

88

在SO问题Best Singleton Implementation In Java中已经讨论了使用枚举来创建单例模式的方式,那么使用这种方式和(省略构造函数)之间有什么不同/优缺点是什么呢?

public enum Elvis {
    INSTANCE;
    private int age;

    public int getAge() {
        return age;
    }
}

然后调用 Elvis.INSTANCE.getAge()

public enum Elvis {
    INSTANCE;
    private int age;

    public static int getAge() {
        return INSTANCE.age;
    }
}

然后调用Elvis.getAge()

4个回答

96

假设您要绑定到将使用给定对象的任何属性的内容,您可以轻松传递 Elvis.INSTANCE,但不能传递 Elvis.class 并期望它查找该属性(除非它有意编码以查找类的静态属性)。

基本上,只有在您想要一个实例时才使用单例模式。如果静态方法对您有效,则只需使用这些方法,不必费心使用枚举。


1
为什么不使用枚举?在Java5+中有更好的单例模式实现方式吗? - jontro
4
@jontro(重新)阅读答案;他建议在必须使用单例模式时使用枚举,但如果可以通过静态方法满足需求,则应避免使用单例模式。 - Miserable Variable
不回答所问的问题。 - Thufir
2
@Thufir:它回答了“有什么区别”的部分——鉴于答案被接受,这似乎是OP最感兴趣的部分。 - Jon Skeet
@LinMa:除此之外,使用序列化效果更佳。《Effective Java第二版》有更多详细信息。 - Jon Skeet
显示剩余11条评论

69

一个很大的优点是当你的单例必须实现一个接口。按照你的例子:

public enum Elvis implements HasAge {
    INSTANCE;
    private int age;

    @Override
    public int getAge() {
        return age;
    }
}

使用:

public interface HasAge {
    public int getAge();
}

使用静态方法无法实现此功能...


1
可以使用静态方法来实现... public static final HasAge INSTANCE = new HasAge() { private int age; @Override public int getAge() { return age; } }; ...所以我仍然在想枚举方法的好处或优点是什么。我猜如果你需要实现两个接口? - Sean Adkinson

9

(有状态的)单例通常用于假装不使用静态变量。如果您实际上不使用公共静态变量,则会欺骗更少的人。


8

我会选择最简单和最清晰的选项。这有些主观,但如果你不知道哪个最清晰,就选择最短的选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接