java 带参数的单例类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14963137/
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
Singleton class with parameter
提问by jnovacho
I'm developing computer vision application and I will need Classifier class. This class will be immutable per run of application and it loads the trained data from disk on initialization. I want to ensure that whole program will have access to same trained data and I want to block reloading the from disk once they are loaded.
我正在开发计算机视觉应用程序,我需要 Classifier 类。这个类在每次应用程序运行时都是不可变的,它在初始化时从磁盘加载经过训练的数据。我想确保整个程序都可以访问相同的训练数据,并且我想在加载后阻止从磁盘重新加载。
What I was considering was to use either static class or singleton. I'm not sure how to load data to static class, because the path to data file is not know at compile time - it will be program argument. So I was thinking of Singleton pattern, but there I don't know how to initialize it dynamically.
我正在考虑使用静态类或单例。我不确定如何将数据加载到静态类,因为在编译时不知道数据文件的路径——它将是程序参数。所以我在考虑单例模式,但我不知道如何动态初始化它。
My idea was to use following:
我的想法是使用以下内容:
class Singleton {
private static Singleton instance;
private Singleton() { ... }
private static SomeDataObject data;
public static Singleton getInstance() {
if(instance == null)
instance = new Singleton();
return instance;
}
public static init(string dataPath){
if(data == null)
loadDataFromFile(dataPath)
}
}
This would not work, because I have no control which method will be called first.
这行不通,因为我无法控制首先调用哪个方法。
I know the proper way would be to create the instance with data at the begining and pass it to all classes and methods which need it, but that's not really general solution. I can keep track of all calls to Classifier in my own code, but if I would make the code as API, this would be a problem.
我知道正确的方法是在开始时使用数据创建实例并将其传递给需要它的所有类和方法,但这并不是真正的通用解决方案。我可以在自己的代码中跟踪对 Classifier 的所有调用,但是如果我将代码设为 API,这将是一个问题。
In short how to initialize singleton at runtime?
总之如何在运行时初始化单例?
回答by Bernhard Barker
I don't think (exactly) what you want to do would work.
我不认为(完全)你想做的事情会奏效。
The below would work:
以下将起作用:
public static void main(String[] args)
{
Singleton.init("somepath");
...
Singleton.getInstance().doingStuff();
...
}
A better implementation may be: (which would cause a NullPointerException
if you try to use it without calling init
first) (not really Singleton any more though)
更好的实现可能是:(NullPointerException
如果您尝试使用它而不init
先调用它会导致 a )(虽然不再是真正的 Singleton)
private static Singleton instance;
private SomeDataObject data;
private Singleton(String path) { loadDataFromFile(path); ... }
public static Singleton getInstance() {
return instance;
}
public static void init(String dataPath){
instance = new Singleton(dataPath);
}
Then there's: (possible bad coding practice aside)
然后是:(除了可能不好的编码实践)
class Main
{
public static void main(String[] args)
{
Singleton.currentPath = "somepath";
...
}
}
class Singleton
{
public static String currentPath = null;
private static Singleton instance;
private SomeDataObject data;
private Singleton(String path) { loadDataFromFile(path); ... }
public static Singleton getInstance() {
if(instance == null && currentPath != null)
instance = new Singleton(currentPath);
return instance;
}
}
which I suppose doesn't really solve much.
我想这并没有真正解决多少问题。
回答by BeCodeMonkey
I use something that is "more" threadsafe than the current winning solution with almost no synchronized used.
我使用的东西比几乎没有使用同步的当前获胜解决方案“更多”线程安全。
import java.util.function.Supplier;
public class InitOnce {
/**
* Marked as final to prevent JIT reordering
*/
private final Supplier<String> theArgs;
private InitOnce(Supplier<String> supplier) {
super();
this.theArgs = supplier;
}
/**
* Uses the arguments to do something
*
* @return
*/
public String doSomething() {
return "Something : " + theArgs.get();
}
/**
* Initializes all the things
*
* @param someArgs
*/
public static synchronized void init(final Supplier<String> someArgs) {
class InitOnceFactory implements Supplier<InitOnce> {
private final InitOnce initOnceInstance = new InitOnce(someArgs);
@Override
public InitOnce get() {
return initOnceInstance;
}
}
if (!InitOnceFactory.class.isInstance(instance)) {
instance = new InitOnceFactory();
} else {
throw new IllegalStateException("Already Initialized");
}
}
private static Supplier<InitOnce> instance = new InitOnceHolder();
/**
* Temp Placeholder supplier
*
*/
private static final class InitOnceHolder implements Supplier<InitOnce> {
@Override
public synchronized InitOnce get() {
if (InitOnceHolder.class.isInstance(instance))
throw new IllegalStateException("Not Initialized");
return instance.get();
}
}
/**
* Returns the instance
*
* @return
*/
public static final InitOnce getInstance() {
return instance.get();
}
}