16
public class MySingleton{
  private static final MySingleton INSTANCE = new MySingleton();
  private MySingleton(){}
  public static getInstance(){
    return INSTANCE;
  }
}

这是实现单例的正确方法吗?如果是,那么 final 关键字的必要性是什么?

4

5 回答 5

2

Final 将确保实例在创建后不可更改。如果你只包括一个构造函数,而没有设置器,那没什么大不了的。没有人可以更改您的实例,而您没有更改它。

将其留在那里以防万一以后更改课程并不是一个坏主意。不变性提供了一些优势(更容易序列化,防止有人在背后更改您的对象等)。

恢复不变性比取出它更难。防御性地编写你的代码,这样以后就不会有人把它搞砸了。

于 2012-12-13T23:43:57.103 回答
2

通常首选的方法是使用枚举

public enum MySingleton {
    INSTANCE;
}

在您的示例中,最终关键字显示了意图并将防止重新分配(=错误),但并非绝对必要。

特别是,变量是静态的,它不需要是最终的就可以在多线程环境中安全地发布。

于 2012-12-13T23:44:03.353 回答
2

在 Java 中实现单例模式没有一种正确的方法,但是使用公共静态最终实例变量是一种很好的方法,前提是您不需要延迟加载并且可以忍受单元测试的后果。

如果单元测试是一个问题并且您仍然想要一个单例,请考虑使用依赖注入。这将允许您配置具有单例生命周期的普通实例。

final 修饰符允许 Java 编译器和运行时做出良好的优化和线程安全决策。我总是将 final 与这种风格的单例声明一起使用。我什至会说允许单例实例可变是一个糟糕的设计选择——因为客户端代码不能再依赖于在进程的生命周期中看到相同的值。

可以使用可配置的工厂类来处理单元测试问题:

private static final MySingleton INSTANCE = MySingletonFactory.create();

...不失去最终的好处。

于 2012-12-14T00:02:17.090 回答
0

不是真的必要。但是使用 final 它不能由单例类本身重置,这会强制执行真正的单例。但是,由于单例是不好的做法,因此可以通过添加 setInstance() 方法使它们可用于单元测试。急的人可以将setInstance定义为private,这样单元测试通过反射调用setInstance。

于 2012-12-13T23:43:08.110 回答
0

似乎没有人讨论这个问题的另一个方面:使单例实例为 final 并不会使其成为不可变的。如果类有额外的实例变量,这些将是单例的一部分,并且可以通过通常的方式进行修改。

于 2018-03-25T09:48:30.413 回答