如何确保JVM中只有一个类实例?
我正在开发一个设计模式,我想确保这里只是Java虚拟机中一个类的一个实例,通过一个点来汇集对某些资源的所有请求,但我不知道它是否可行。
我只能想到一种计算类实例的方法,并在创建第一个实例后销毁所有实例。
这是一种正确的方法吗? 如果没有,还有其他方法吗?
使用单例模式。 最简单的实现包括一个private constructor
和一个保存其结果的field
,以及一个名为getInstance()
的static
访问器方法。
私有字段可以从静态初始化程序块中分配,或者更简单地使用初始化程序分配。 getInstance()
方法(必须是公共的)然后只返回此实例,
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"; } }
请注意,在Java中不需要在getInstance()
方法(设计模式中提倡getInstance()
中使用“延迟求值”的方法,因为Java已经使用“延迟加载”。除非getInstance()
否则您的单例类可能不会被加载getInstance()
被调用,所以没有必要尝试推迟单例构造,直到需要getInstance()
测试单例变量为null
并在那里创建单例。
使用这个类同样简单:只需获取并保留引用,并在其上调用方法:
public class SingletonDemo { public static void main(String[] args) { Singleton tmp = Singleton.getInstance(); tmp.demoMethod(); } }
一些评论员认为单例还应该提供一个公共最终clone()
方法,它只抛出一个exception,以避免“欺骗”和clone()
单例的子类。 但是,很明显只有私有构造函数的类不能被子类化,所以这种偏执似乎不是必需的。
你想要Singleton
模式。 关于如何正确实现这一点有一个很好的讨论 。 如果你这样做,那么只有一个类的实例。
基本上你要做的是创建一个类,在静态级别保存该类的单个实例化对象,并提供一个静态访问器来获取它( getInstance()
或类似)。 使构造函数最终,这样人们就无法创建自己的实例。 上面的链接有很多关于如何做到这一点的好建议。
这是众所周知的Singleton模式:您可以按如下方式实现:
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();
但在文学中, 单身人士通常被认为是一个糟糕的设计理念 。 当然,这在某种程度上取决于具体情况,但大多数程序员都反对。 只说出来,不要向信使开枪……
有一种思想流派认为单身人士模式实际上是一种反模式。
考虑到你只希望拥有A类的A类,那么另一种选择是拥有一个构建器或工厂类,它本身限制了A类对象数量的创建,并且可以通过一个简单的计数器。 优点是A级不再需要担心,它专注于其真正的目的。 每个使用它的类不再需要担心它是单例(不再需要getInstance()调用)。
使用枚举。 在Java中,enum是创建单例的唯一真正方法。 私有构造函数仍然可以通过reflection来调用。
有关更多详细信息,请参阅此StackOverflow问题: 使用Enum实现Singleton(在Java中)
讨论: http : //javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-java.html
我只能想到一种计算类实例的方法,并在创建第一个实例后销毁所有实例。 这是一种正确的方法吗? 如果没有,还有其他方法吗?
正确的技术方法是将类的所有构造函数声明为private
以便类的实例只能由类本身创建。 然后你只编写类来创建一个实例。
根据“Singleton”设计模式,其他答案显示了实现这一点的一些方法。 但是,实现像这样的单例有一些缺点,包括使编写unit testing变得更加困难。
我更喜欢lazy singleton类,它会覆盖readResolve方法。
对于Serializable和Externalizable类,readResolve方法允许类在返回到调用方之前替换/解析从流中读取的对象。 通过实现readResolve方法,类可以直接控制被反序列化的自己的实例的类型和实例。
使用/ 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
关键字禁止通过子类扩展此类 -
private
构造函数禁止在调用者类中使用new
运算符创建直接对象 -
readResolve
禁止在对象反序列化期间创建多个类实例
为此你需要使用单例模式,我只是发布了一个可能对你理解有用的演示代码。
例如:如果我只想为此Connect
类使用一个对象:
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
关键字来创建新实例。
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(); } }