Java 如何创建单例类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4362911/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create a singleton class
提问by Arun P Johny
What is the best/correct way to create a singleton class in java?
在java中创建单例类的最佳/正确方法是什么?
One of the implementation I found is using a private constructor and a getInstance() method.
我发现的实现之一是使用私有构造函数和 getInstance() 方法。
package singleton;
public class Singleton {
private static Singleton me;
private Singleton() {
}
public static Singleton getInstance() {
if (me == null) {
me = new Singleton();
}
return me;
}
}
But is implementation fails in the following test case
但是在以下测试用例中实现失败
package singleton;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test {
/**
* @param args
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
Singleton singleton1 = Singleton.getInstance();
System.out.println(singleton1);
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton2);
Constructor<Singleton> c = Singleton.class
.getDeclaredConstructor((Class<?>[]) null);
c.setAccessible(true);
System.out.println(c);
Singleton singleton3 = c.newInstance((Object[]) null);
System.out.println(singleton3);
if(singleton1 == singleton2){
System.out.println("Variable 1 and 2 referes same instance");
}else{
System.out.println("Variable 1 and 2 referes different instances");
}
if(singleton1 == singleton3){
System.out.println("Variable 1 and 3 referes same instance");
}else{
System.out.println("Variable 1 and 3 referes different instances");
}
}
}
How to resolve this?
如何解决这个问题?
Thank you
谢谢
采纳答案by BalusC
As per the comment on your question:
根据对您的问题的评论:
I've a properties file containing some keys value pairs, which is need across the application, that is why I was thinking about a singleton class. This class will load the properties from a file and keep it and you can use it from anywhere in the application
我有一个包含一些键值对的属性文件,这是整个应用程序都需要的,这就是我考虑单例类的原因。此类将从文件中加载属性并保留它,您可以在应用程序的任何位置使用它
Don't use a singleton. You apparently don't need one-time lazyinitialization (that's where a singleton is all about). You want one-time directinitialization. Just make it static and load it in a static initializer.
不要使用单例。您显然不需要一次性延迟初始化(这就是单例的全部意义所在)。您需要一次性直接初始化。只需将其设为静态并将其加载到静态初始化程序中即可。
E.g.
例如
public class Config {
private static final Properties PROPERTIES = new Properties();
static {
try {
PROPERTIES.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
} catch (IOException e) {
throw new ExceptionInInitializerError("Loading config file failed.", e);
}
}
public static String getProperty(String key) {
return PROPERTIES.getProperty(key);
}
// ...
}
回答by Ram
I think you can check whether an instance already exists in the constructor and if exists throw an exception
我认为您可以检查构造函数中是否已存在实例,如果存在则抛出异常
if(me != null){
throw new InstanceAlreadyExistsException();
}
回答by cdhowie
If you are using reflection to pierce encapsulation, you should not be surprised when behavior of your class is altered in incorrect ways. Private members are supposed to be private to the class. By using reflection to access them you are intentionally breaking the behavior of the class, and the resultant "duplicate singleton" is expected.
如果您使用反射来突破封装,当您的类的行为以不正确的方式改变时,您不应感到惊讶。私有成员应该是班级私有的。通过使用反射来访问它们,您有意破坏了类的行为,并且预期会产生“重复的单例”。
In short: Don't do that.
简而言之:不要那样做。
Also, you might consider creating the singleton instance in a static constructor. Static constructors are synchronized and will only run once. Your current class contains a race condition -- if two separate threads call getInstance()
when it has not been previously called, there is a possibility that two instances will be created, one of them being exclusive to one of the threads, and the other becoming the instance that future getInstance()
calls will return.
此外,您可能会考虑在静态构造函数中创建单例实例。静态构造函数是同步的,并且只会运行一次。您当前的类包含竞争条件——如果两个单独的线程getInstance()
在之前未被调用时调用,则可能会创建两个实例,其中一个是其中一个线程专有的,另一个成为实例未来的getInstance()
电话将返回。
回答by Chu Xiwen
just follow the singleton pattern class diagram,
只需按照单例模式类图,
SingletonClass - singletonObject: SingletonClass - SingletonClass() + getObject(): SingletonClass
SingletonClass - singletonObject: SingletonClass - SingletonClass() + getObject(): SingletonClass
Key point,
重点,
- private your constructor
- the instance of your class should be inside the class
- provide the function to return your instance
- 私有你的构造函数
- 你的类的实例应该在类内
- 提供返回实例的函数
Some code,
一些代码,
public class SingletonClass {
private static boolean hasObject = false;
private static SingletonClass singletonObject = null;
public static SingletonClass getObject() {
if (hasObject) {
return singletonObject;
} else {
hasObject = true;
singletonObject = new SingletonClass();
return singletonObject;
}
}
private SingletonClass() {
// Initialize your object.
}
}
回答by kalyani chaudhari
Best way to create Singleton Class in java is using Enums.
在 java 中创建单例类的最佳方法是使用枚举。
Example as below :
示例如下:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
enum SingleInstance{
INSTANCE;
private SingleInstance() {
System.out.println("constructor");
}
}
public class EnumSingletonDemo {
public static void main (String args[]) throws FileNotFoundException, IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
SingleInstance s=SingleInstance.INSTANCE;
SingleInstance s1=SingleInstance.INSTANCE;
System.out.println(s.hashCode() + " "+s1.hashCode());//prints same hashcode indicates only one instance created
//------- Serialization -------
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("sample.ser"));
oos.writeObject(s);
oos.close();
//------- De-Serialization -------
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("sample.ser"));
SingleInstance s2=(SingleInstance) ois.readObject();
System.out.println("Serialization :: "+s.hashCode()+" "+s2.hashCode());// prints same hashcodes because JVM handles serialization in case of enum(we dont need to override readResolve() method)
//-----Accessing private enum constructor using Reflection-----
Class c=Class.forName("SingleInstance");
Constructor co=c.getDeclaredConstructor();//throws NoSuchMethodException
co.setAccessible(true);
SingleInstance newInst=(SingleInstance) co.newInstance();
}
}
NoSuchMethodException is thrown because we can't create another instance of enum 'SingleInstance' through its private constructor using Reflection.
抛出 NoSuchMethodException 是因为我们无法使用反射通过其私有构造函数创建 enum 'SingleInstance' 的另一个实例。
In Case of Serialization enum implements serializable interface by default.
在序列化的情况下,枚举默认实现可序列化接口。
回答by Ravindra babu
I will implement singleton in below way.
我将通过以下方式实现单例。
From Singleton_patterndescribed by wikiepdia by using Initialization-on-demand holder idiom
来自维基百科描述的Singleton_pattern使用 Initialization-on-demand holder idiom
This solution is thread-safe without requiring special language constructs (i.e. volatile
or synchronized
这个解决方案是线程安全的,不需要特殊的语言结构(即volatile
或synchronized
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;
}
}