Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 单例类设计-空对象_Java_Multithreading_Singleton_Class Design - Fatal编程技术网

Java 单例类设计-空对象

Java 单例类设计-空对象,java,multithreading,singleton,class-design,Java,Multithreading,Singleton,Class Design,我和一位同事正在进行辩论: 我们有一个单例类,它在代码库中的多个位置使用 最初,类的设计方式是,您可以获取类对象,但该对象不会完全初始化 我的意思是: mySingleton.getInstance().SomeMethod(); SomeMethod将导致错误,因为类未初始化。要使类正常工作,必须执行以下操作: mySingleton.getInstance().initObject(); mySingleton.getInstance().SomeMethod(); 无论如何,我的争论

我和一位同事正在进行辩论:

我们有一个单例类,它在代码库中的多个位置使用

最初,类的设计方式是,您可以获取类对象,但该对象不会完全初始化

我的意思是:

mySingleton.getInstance().SomeMethod();
SomeMethod
将导致错误,因为类未初始化。要使类正常工作,必须执行以下操作:

mySingleton.getInstance().initObject();

mySingleton.getInstance().SomeMethod();
无论如何,我的争论是构造函数(用第一个get实例调用)应该调用
initObject
,这样就不会抛出错误

你觉得怎么样


我的同事喜欢另一种方式,因此他知道类何时初始化。(也就是说,他在一行特定的代码中调用
initObject
,并希望没有其他东西需要它)。

在我看来,拥有
initObject()
方法是不必要的,而且似乎违背了拥有单例的目的。我觉得任何使用您的单例的人都会假设,当他们调用
getInstance()
时,他们会得到该类的完整功能实例。为什么要求某人在使用它之前调用
initObject()。为什么有人需要知道对象何时被初始化,难道不应该假设检索到的对象已经被初始化了吗?

您比您的同事更接近Java中实现singleton模式的通常方式。请看一看。在这里,您可以找到3种最常见的Java实现:

传统简易方法 “比尔·普格的解决方案” 使用同步的传统简单方法 它们都没有使用单独的
initObject()
方法(初始化应该在私有构造函数中)。另外请注意,如果您有一个单独的、公共的
initObject()
方法,则可能会出现多线程问题

顺便说一句,就我个人而言,我宁愿使用“比尔·普格”替代方案,但这三种方法都是有效的

编辑在类Esko评论之后,我添加了以下实现,这在Wikipedia上是不可用的。我只想补充一点:1)singleton实例不是像上面的3个选项那样懒洋洋地创建的;2) 因为它是枚举,所以不能扩展任何类;这是非常非常奇怪的。但它似乎在Java社区中大肆宣传,所以它就在这里:

枚举方式
我将在getInstance()方法中进行初始化检查:

。。。并将initialize()方法设为私有

编辑:显然我误解了这个问题。主要问题是initObject()应该在构造函数内部还是外部。正确答案可能取决于实际问题,但我认为它通常应该在构造函数内部,因为如果将initObject()方法置于构造函数外部的唯一目的是告诉每个人初始化发生的位置,那么您最好写一条注释:

// Attention everyone!! Object is initialized here!!1!11!
MySingleton instance = MySingleton.getInstance();

// Object is NOT initialized here!!11!1!!
MySingleton instance2 = MySingleton.getInstance();

首先,你的方法更接近单身的想法

初始化内容对Singleton的用户应该是透明的。这样做的一个好方法甚至不是使用构造函数,而是将initObject代码放在一个静态块中,
在类定义的开头。

我不明白为什么需要initObject方法。若这是一个单例,那个么该方法无论如何只会得到一次调用。我只是将方法内联到构造函数本身中。

如果可以避免,请不要使用
initObject
方法

在两种情况下可能不可避免:

  • 单例的初始化必须在应用程序启动过程中的某个特定点进行,这是强制进行初始化的唯一合理方法

  • singleton的初始化需要只能以这种方式提供的参数;e、 g.由命令行参数构造的参数

如果您必须有一个init方法,那么如果它被调用两次,它应该抛出一个异常。如果异常调用得太早,那么
getInstance()
方法也可以抛出异常


这些应该应用于@rsenna答案中的“传统”示例。

如果您想遵循这种方式,必须将初始化检查放入
同步的
块中(以获得线程安全)。+1表示“如果唯一目的是放置initObject()构造函数之外的方法是告诉每个人初始化发生的位置,你也可以写一条注释”。在许多情况下,最好的解决方案是首先不使用单例,而是使用普通的实例对象,并简单地将实例注入到需要它的类中(手动将其传递到构造函数或类似的构造函数中,或使用IoC框架)。奇怪的是,所有这些都没有使用enum,这是在Java中实现单例的最简单方法。@Esko:事实上,我发现enum实现在语义上有点奇怪(基本上是Java WTF),但好的,我将编辑我的答案并添加它…谢谢团队,我同意你们所有人的意见。我认为initObject是一些令人沮丧的调试的结果..或者其他…无论如何,得到反馈很好。谢谢团队,我同意你们所有人的意见。我认为initObject是一些令人沮丧的调试的结果..或者其他…无论如何,得到反馈很好反馈,再次感谢。
public class Singleton {
    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    /**
     * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
     * or the first access to SingletonHolder.INSTANCE, not before.
     */
    private static class SingletonHolder { 
        public static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
public class Singleton {
    // volatile is needed so that multiple threads can reconcile the instance
    // semantics for volatile changed in Java 5.
    private volatile static Singleton singleton;

    private Singleton() {}

    // synchronized keyword has been removed from here
    public static Singleton getSingleton() {
        // needed because once there is singleton available no need to acquire
        // monitor again & again as it is costly
        if (singleton == null) {
            synchronized (Singleton.class) {
                // this is needed if two threads are waiting at the monitor at the
                // time when singleton was getting instantiated
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
public enum Singleton {
    INSTANCE;
    Singleton() {
        /* Your init code goes here */
    }
}
public static MySingleton getInstance() {
  if (! isInitialized)
    initialize();
  return instance;
}
// Attention everyone!! Object is initialized here!!1!11!
MySingleton instance = MySingleton.getInstance();

// Object is NOT initialized here!!11!1!!
MySingleton instance2 = MySingleton.getInstance();