public class MySingleton{
private static final MySingleton INSTANCE = new MySingleton();
private MySingleton(){}
public static getInstance(){
return INSTANCE;
}
}
这是实现单例的正确方法吗?如果是,那么 final 关键字的必要性是什么?
Final 将确保实例在创建后不可更改。如果你只包括一个构造函数,而没有设置器,那没什么大不了的。没有人可以更改您的实例,而您没有更改它。
将其留在那里以防万一以后更改课程并不是一个坏主意。不变性提供了一些优势(更容易序列化,防止有人在背后更改您的对象等)。
恢复不变性比取出它更难。防御性地编写你的代码,这样以后就不会有人把它搞砸了。
通常首选的方法是使用枚举
public enum MySingleton {
INSTANCE;
}
在您的示例中,最终关键字显示了意图并将防止重新分配(=错误),但并非绝对必要。
特别是,变量是静态的,它不需要是最终的就可以在多线程环境中安全地发布。
在 Java 中实现单例模式没有一种正确的方法,但是使用公共静态最终实例变量是一种很好的方法,前提是您不需要延迟加载并且可以忍受单元测试的后果。
如果单元测试是一个问题并且您仍然想要一个单例,请考虑使用依赖注入。这将允许您配置具有单例生命周期的普通实例。
final 修饰符允许 Java 编译器和运行时做出良好的优化和线程安全决策。我总是将 final 与这种风格的单例声明一起使用。我什至会说允许单例实例可变是一个糟糕的设计选择——因为客户端代码不能再依赖于在进程的生命周期中看到相同的值。
可以使用可配置的工厂类来处理单元测试问题:
private static final MySingleton INSTANCE = MySingletonFactory.create();
...不失去最终的好处。
不是真的必要。但是使用 final 它不能由单例类本身重置,这会强制执行真正的单例。但是,由于单例是不好的做法,因此可以通过添加 setInstance() 方法使它们可用于单元测试。急的人可以将setInstance定义为private,这样单元测试通过反射调用setInstance。
似乎没有人讨论这个问题的另一个方面:使单例实例为 final 并不会使其成为不可变的。如果类有额外的实例变量,这些将是单例的一部分,并且可以通过通常的方式进行修改。