如何确保 JVM 中只有一个 class 实例?
How to make sure that there is just one instance of class in JVM?
我正在开发一种设计模式,我想确保这只是 Java 虚拟机中 class 的一个实例,以便通过单个点,但不知道可不可以。
我只能想办法计算一个class的实例,并在创建第一个实例后销毁所有实例。
这是正确的方法吗?如果不行,还有别的办法吗?
您需要 Singleton
模式。 excellent discussion 介绍了如何正确实施它。如果你做对了,将永远只有一个 class 的实例。
基本上您要做的是创建一个 class,在静态级别保存该 class 的单个实例化对象,并提供一个静态访问器来获取它(getInstance()
或类似的)。使构造函数成为最终的,这样人们就不能突然创建自己的实例。上面的 link 有很多关于如何做到这一点的好建议。
使用单例模式。最简单的实现包括一个 private constructor
和一个 field
来保存它的结果,以及一个 static
访问器方法,其名称类似于 getInstance()
。
私有字段可以从静态初始化程序块中分配,或者更简单地说,使用初始化程序。 getInstance()
方法(必须是public)然后简单地returns这个实例,
public class Singleton {
private static Singleton instance;
/**
* A private Constructor prevents any other class from
* instantiating.
*/
private Singleton() {
// nothing to do this time
}
/**
* The Static initializer constructs the instance at class
* loading time; this is to simulate a more involved
* construction process (it it were really simple, you'd just
* use an initializer)
*/
static {
instance = new Singleton();
}
/** Static 'instance' method */
public static Singleton getInstance() {
return instance;
}
// other methods protected by singleton-ness would be here...
/** A simple demo method */
public String demoMethod() {
return "demo";
}
}
注意getInstance()
方法中使用“懒惰求值”的方法(
在设计模式中提倡),在 Java 中不是必需的,因为 Java 已经使用了“lazy
加载中。”你的单例 class 可能不会被加载,除非它 getInstance()
被调用,因此没有必要尝试将单例构造推迟到需要时
通过 getInstance()
测试 null
的单例变量并创建单例
那里。
使用这个 class 同样简单:只需获取并保留引用,然后在其上调用方法:
public class SingletonDemo {
public static void main(String[] args) {
Singleton tmp = Singleton.getInstance();
tmp.demoMethod();
}
}
一些评论者认为单例也应该提供一个 public final
clone()
只抛出异常的方法,以避免子classes“欺骗”和
clone()
单例。但是,很明显 class 只有一个私有构造函数
不能被子classed,所以这种偏执似乎没有必要。
这就是众所周知的单例模式:您可以按如下方式实现它:
public class SingletonClass {
//this field contains the single instance every initialized.
private static final instance = new SingletonClass();
//constructor *must* be private, otherwise other classes can make an instance as well
private SingletonClass () {
//initialize
}
//this is the method to obtain the single instance
public static SingletonClass getInstance () {
return instance;
}
}
然后您调用实例(就像您构建非单例一样):
SingletonClass.getInstance();
但在文献中,单例通常被认为是bad design idea。当然,这总是在某种程度上取决于具体情况,但大多数程序员都反对这样做。只是说说而已,不要对着信使开枪...
因为你需要使用单例模式,我只是发布了一个演示代码,可能有助于你的理解。
例如:如果我只想要一个对象 Connect
class:
public final class Connect {
private Connect() {}
private volatile static Connect connect = null;
public static Connect getinstance() {
if(connect == null) {
synchronized (Connect.class) {
connect = new Connect();
}
}
return connect;
}
}
这里的构造函数是私有的,所以没有人可以使用new
关键字来创建一个新的实例。
I can only think of a way to count instances of a class and destroy all instance after first is created. Is this a right approach ? If not, is there any other way ?
正确的技术方法是将 class 的所有构造函数声明为 private
,这样 class 的实例只能由 class 创建本身。然后你编码 class 只创建一个实例。
其他答案显示了根据 "Singleton" 设计模式实现此目的的一些方法。但是,像这样实现单例有一些缺点,包括使编写单元测试变得更加困难。
有一种观点认为单例模式实际上是一种反模式。
考虑到您只希望拥有一个 class A,那么另一种选择是拥有一个构建器或工厂 class,它本身限制了 Class A,这可以通过一个简单的计数器来实现。
好处是ClassA不用再操心了,专心于自己真正的目的。每个使用它的 class 都不再需要担心它是一个单例(不再需要 getInstance() 调用)。
使用枚举。在 Java 中,枚举是创建单例的唯一正确方法。仍然可以通过反射调用私有构造函数。
有关详细信息,请参阅此 Whosebug 问题:
Implementing Singleton with an Enum (in Java)
讨论:
http://javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-java.html
class A{
private A(){
}
public static A creator(A obj){
A ob=new A();
return ob;
}
void test(){
System.out.println("The method is called");
}
}
class Demo{
public static void main(String[] args){
A ob=null;
ob=A.creator(ob);
ob.test();
}
}
我更喜欢惰性单例 class,它会覆盖 readResolve 方法。
For Serializable and Externalizable classes, the readResolve method allows a class to replace/resolve the object read from the stream before it is returned to the caller. By implementing the readResolve method, a class can directly control the types and instances of its own instances being deserialized.
惰性单例使用 /Initialization-on-demand_holder_idiom:
public final class LazySingleton {
private LazySingleton() {}
public static LazySingleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazySingleton INSTANCE = new LazySingleton();
}
private Object readResolve() {
return LazyHolder.INSTANCE;
}
}
要点:
final
关键字禁止通过 sub-classing 扩展此 class
private
构造函数禁止在调用方 classes 中使用 new
运算符直接创建对象
readResolve
禁止在对象反序列化期间创建 class 的多个实例
我正在开发一种设计模式,我想确保这只是 Java 虚拟机中 class 的一个实例,以便通过单个点,但不知道可不可以。
我只能想办法计算一个class的实例,并在创建第一个实例后销毁所有实例。
这是正确的方法吗?如果不行,还有别的办法吗?
您需要 Singleton
模式。 excellent discussion 介绍了如何正确实施它。如果你做对了,将永远只有一个 class 的实例。
基本上您要做的是创建一个 class,在静态级别保存该 class 的单个实例化对象,并提供一个静态访问器来获取它(getInstance()
或类似的)。使构造函数成为最终的,这样人们就不能突然创建自己的实例。上面的 link 有很多关于如何做到这一点的好建议。
使用单例模式。最简单的实现包括一个 private constructor
和一个 field
来保存它的结果,以及一个 static
访问器方法,其名称类似于 getInstance()
。
私有字段可以从静态初始化程序块中分配,或者更简单地说,使用初始化程序。 getInstance()
方法(必须是public)然后简单地returns这个实例,
public class Singleton {
private static Singleton instance;
/**
* A private Constructor prevents any other class from
* instantiating.
*/
private Singleton() {
// nothing to do this time
}
/**
* The Static initializer constructs the instance at class
* loading time; this is to simulate a more involved
* construction process (it it were really simple, you'd just
* use an initializer)
*/
static {
instance = new Singleton();
}
/** Static 'instance' method */
public static Singleton getInstance() {
return instance;
}
// other methods protected by singleton-ness would be here...
/** A simple demo method */
public String demoMethod() {
return "demo";
}
}
注意getInstance()
方法中使用“懒惰求值”的方法(
在设计模式中提倡),在 Java 中不是必需的,因为 Java 已经使用了“lazy
加载中。”你的单例 class 可能不会被加载,除非它 getInstance()
被调用,因此没有必要尝试将单例构造推迟到需要时
通过 getInstance()
测试 null
的单例变量并创建单例
那里。
使用这个 class 同样简单:只需获取并保留引用,然后在其上调用方法:
public class SingletonDemo {
public static void main(String[] args) {
Singleton tmp = Singleton.getInstance();
tmp.demoMethod();
}
}
一些评论者认为单例也应该提供一个 public final
clone()
只抛出异常的方法,以避免子classes“欺骗”和
clone()
单例。但是,很明显 class 只有一个私有构造函数
不能被子classed,所以这种偏执似乎没有必要。
这就是众所周知的单例模式:您可以按如下方式实现它:
public class SingletonClass {
//this field contains the single instance every initialized.
private static final instance = new SingletonClass();
//constructor *must* be private, otherwise other classes can make an instance as well
private SingletonClass () {
//initialize
}
//this is the method to obtain the single instance
public static SingletonClass getInstance () {
return instance;
}
}
然后您调用实例(就像您构建非单例一样):
SingletonClass.getInstance();
但在文献中,单例通常被认为是bad design idea。当然,这总是在某种程度上取决于具体情况,但大多数程序员都反对这样做。只是说说而已,不要对着信使开枪...
因为你需要使用单例模式,我只是发布了一个演示代码,可能有助于你的理解。
例如:如果我只想要一个对象 Connect
class:
public final class Connect {
private Connect() {}
private volatile static Connect connect = null;
public static Connect getinstance() {
if(connect == null) {
synchronized (Connect.class) {
connect = new Connect();
}
}
return connect;
}
}
这里的构造函数是私有的,所以没有人可以使用new
关键字来创建一个新的实例。
I can only think of a way to count instances of a class and destroy all instance after first is created. Is this a right approach ? If not, is there any other way ?
正确的技术方法是将 class 的所有构造函数声明为 private
,这样 class 的实例只能由 class 创建本身。然后你编码 class 只创建一个实例。
其他答案显示了根据 "Singleton" 设计模式实现此目的的一些方法。但是,像这样实现单例有一些缺点,包括使编写单元测试变得更加困难。
有一种观点认为单例模式实际上是一种反模式。
考虑到您只希望拥有一个 class A,那么另一种选择是拥有一个构建器或工厂 class,它本身限制了 Class A,这可以通过一个简单的计数器来实现。 好处是ClassA不用再操心了,专心于自己真正的目的。每个使用它的 class 都不再需要担心它是一个单例(不再需要 getInstance() 调用)。
使用枚举。在 Java 中,枚举是创建单例的唯一正确方法。仍然可以通过反射调用私有构造函数。
有关详细信息,请参阅此 Whosebug 问题: Implementing Singleton with an Enum (in Java)
讨论: http://javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-java.html
class A{
private A(){
}
public static A creator(A obj){
A ob=new A();
return ob;
}
void test(){
System.out.println("The method is called");
}
}
class Demo{
public static void main(String[] args){
A ob=null;
ob=A.creator(ob);
ob.test();
}
}
我更喜欢惰性单例 class,它会覆盖 readResolve 方法。
For Serializable and Externalizable classes, the readResolve method allows a class to replace/resolve the object read from the stream before it is returned to the caller. By implementing the readResolve method, a class can directly control the types and instances of its own instances being deserialized.
惰性单例使用 /Initialization-on-demand_holder_idiom:
public final class LazySingleton {
private LazySingleton() {}
public static LazySingleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazySingleton INSTANCE = new LazySingleton();
}
private Object readResolve() {
return LazyHolder.INSTANCE;
}
}
要点:
final
关键字禁止通过 sub-classing 扩展此 class
private
构造函数禁止在调用方 classes 中使用 readResolve
禁止在对象反序列化期间创建 class 的多个实例
new
运算符直接创建对象