在简单单例实例化中获取 ExceptionInInitializerError

发布于 2024-09-28 05:26:10 字数 787 浏览 9 评论 0原文

我一定做了一些非常愚蠢的事情,但是当我尝试在单例中实例化一个对象时,我收到了 ExceptionInInitializerError :

class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  // Do I instantiate obj here???
  private MySingleton() {
    //obj = new OtherObject();
  }

  // Or here?
  {
    //obj = new OtherObject();
  }

  // Or where? ...

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

我应该在构造函数中创建另一个对象,还是对于单例来说它总是应该为空?我在构造函数和初始化块中都遇到异常...

这是 main():

public static void main(String[] args) {
    try {
        MySingleton singleton = MySingleton.getInstance();
    } catch (Error e) {
        System.err.println("Error!");
    }
}

I must be doing something very silly, but I'm getting a ExceptionInInitializerError when I try to instantiate an object in my Singleton:

class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  // Do I instantiate obj here???
  private MySingleton() {
    //obj = new OtherObject();
  }

  // Or here?
  {
    //obj = new OtherObject();
  }

  // Or where? ...

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

Should I make the other object in the constructor, or is that always supposed to be empty for singletons? I get the exception in both the constructor and the initializer block...

Here's the main():

public static void main(String[] args) {
    try {
        MySingleton singleton = MySingleton.getInstance();
    } catch (Error e) {
        System.err.println("Error!");
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

时间海 2024-10-05 05:26:11

静态初始化部分用于初始化标记为静态的类的成员。由于 OtherObject obj 不是静态的,因此不应在那里初始化。正确的地方是在构造函数中初始化它。

如果在构造函数中有 obj = new OtherObject() 时出现 ExceptionInInitializerError,则问题可能出在另一个类(也许是 OtherObject?) 上,该类未正确初始化静态成员。

Static initialization sections are for initializing members of the class marked static. Since OtherObject obj isn't static it should not be initialized there. The correct place is to initialize it in the constructor.

If you are getting an ExceptionInInitializerError when you have obj = new OtherObject() in the constructor, the problem may be with another class (OtherObject perhaps?) that is incorrectly initializing static members.

川水往事 2024-10-05 05:26:11

您应该在构造函数中实例化 OtherObj 。给出错误的确切代码是什么?

编辑 - 以下内容对我有用

class MySingleton {

  private static MySingleton instance = null;
  private Integer obj;


  private MySingleton() {
    obj = new Integer(2);
  }


  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

,然后我只需从主循环中调用 getInstance 。您可能想查看

http://en.wikipedia.org/wiki/Singleton_pattern#Java

you should instantiate OtherObj in your constructor. What is the exact code that is giving the error?

edit -- The following worked for me

class MySingleton {

  private static MySingleton instance = null;
  private Integer obj;


  private MySingleton() {
    obj = new Integer(2);
  }


  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

and then I just call getInstance from a main loop. You might want to look at

http://en.wikipedia.org/wiki/Singleton_pattern#Java

无尽的现实 2024-10-05 05:26:11
class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  private MySingleton() {
      obj = new OtherObject();
  }

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}
class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  private MySingleton() {
      obj = new OtherObject();
  }

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}
人│生佛魔见 2024-10-05 05:26:11

答案很简单,不要使用单例。虽然 GoF 书中有一些好的想法,但单例模式并不是其中之一。

正如其他人在上游所说,单例的正确线程安全使用很棘手,请参阅

IBM 关于线程安全单例的文章

实际上,单例实现的所有内容都是全局对象。这很糟糕,它污染了名称空间。它使得正确的单元测试(Junit 等)变得更加困难,甚至不可能。你永远不需要它。简单的静态工厂类是更干净的代码,避免了全局污染并且代码更少。

The answer is simple, don't use Singletons. While the GoF book has some good ideas, the singleton pattern is not one of them.

As others have said upthread, the proper thread safe use of singletons is tricky, see

IBM article on thread safe singletons

In reality, all a Singleton implements is a global object. This is bad, it pollutes the namespace. It makes proper unit testing (Junit, etc) much harder if not impossible. You don't need it, ever. A simple static factory class is cleaner code, avoids the global pollution and is less code.

喜你已久 2024-10-05 05:26:11

你的 Singleton 类在这里没有问题。我猜想 OtherObject 类的构造函数有问题。

正确的语法是:

class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  private MySingleton() {
    obj = new OtherObject();
  }

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

现在,您只需向我们提供有关 OtherObject 的更多信息:-)

Your Singleton class is not at fault here. I would guess a problem in the contructor of the OtherObject class.

A correct syntax would be:

class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  private MySingleton() {
    obj = new OtherObject();
  }

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

Now, you just need to give us more information about the OtherObject :-)

温柔少女心 2024-10-05 05:26:10

您可以通过消除延迟初始化风险(您目前正在为此付费)来避免一些混乱在例外情况下)。既然您实际上只是返回静态实例,为什么不在运行时创建该静态实例(即,不要等待 null):

class MySingleton {

  private static MySingleton instance = new MySingleton();

  // You could do this here or in the constructor
  // private OtherObject obj = new OtherObject();

  /** Use this if you want to do it in the constructor instead. */
  private OtherObject obj;

  private MySingleton() {
      obj = new OtherObject();
  }

  /** Now you can just return your static reference */
  public static MySingleton getInstance() {
      return instance;
  }

}

如果您注意到,现在一切都是确定性且简单的。您的 MySingleton.instance 在运行时填充,并通过静态方法 MySingleton.getInstance() 访问。

我意识到这与原始 GOF 设计模式书中的确切模式不匹配,但您会注意到该类的用法实际上是相同的。

编辑:跟进其他答案和评论中提出的一些线程安全点,我将尝试说明问题和 GOF 书中最初提出的解决方案如何是非线程的安全的。要获得更好的参考,请参阅我拥有并放在 ACM / Safari 在线书架上的 Java Concurrency in Practice。坦率地说,它是比我草拟的示例更好的来源,但是,嘿,我们可以努力......

所以,想象我们有两个名为 Thread1 和 Thread2 的线程,巧合的是,每个线程同时命中 MySingleton.getInstance() 方法。这在现代多核超线程系统中是完全可能的。现在,即使这两个线程碰巧同时命中该方法的入口点,也无法保证哪一个线程会命中任何特定语句。因此,您可能会看到类似这样的内容:

// Note that instance == null as we've never called the lazy getInstance() before.

Thread1: if (instance == null)
Thread2: if (instance == null) // both tests pass - DANGER
Thread1:     instance = new MySingleton();
Thread2:     instance = new MySingleton(); // Note - you just called the constructor twice
Thread1: return instance; // Two singletons were actually created 
Thread2: return instance; // Any side-effects in the constructor were called twice

if-null 测试中说明的问题称为 竞争条件。你无法知道谁会在什么时候发表什么声明。结果,就好像两条线程都在互相竞争,冲向悬崖。

如果您查看我的示例的相同类型的检查,其中两个线程仍然同时命中 getInstance(),您会看到类似这样的内容:

Thread1: return instance;
Thread2: return instance;

简单化,是的,但这就是我的观点。该对象很久以前就被构造过一次,并且线程可以依赖它的值是一致的。不存在种族。

注意:您仍然需要担心 OtherObject 构造函数的内容。教训是:并发很难。如果您要使构造函数线程安全(您应该这么做),请确保 OtherObject 的作者也以同样的方式为您提供帮助。

You can avoid some of your confusion by eliminating the lazy initialization risk (which you're currently paying for in the exception). Since you're really just returning your static instance, why not just create that static instance at run time (i.e., don't wait for null):

class MySingleton {

  private static MySingleton instance = new MySingleton();

  // You could do this here or in the constructor
  // private OtherObject obj = new OtherObject();

  /** Use this if you want to do it in the constructor instead. */
  private OtherObject obj;

  private MySingleton() {
      obj = new OtherObject();
  }

  /** Now you can just return your static reference */
  public static MySingleton getInstance() {
      return instance;
  }

}

If you notice, now everything is deterministic and straightforward. Your MySingleton.instance is populated at runtime and is accessed via the static method MySingleton.getInstance().

I realize that this doesn't match the exact pattern of the original GOF design patterns book but you'll notice that the usage of the class is effectively the same.

EDIT: following up on some of the thread safety points raised in other answers and comments, I'm going to try to illustrate how the original proposed solution in the question and in the GOF book is non-thread safe. For a better reference, see Java Concurrency in Practice which I own and have on my ACM / Safari online bookshelf. It is frankly a better source than my sketched example but, hey, we can but strive....

So, imagine we have two threads named Thread1 and Thread2 and, coincidentally, each hits the MySingleton.getInstance() method at the same moment. This is entirely possible in a modern multicore hyperthreaded system. Now, even though these two threads happened to hit the entry point of this method at the same time, there's no assurance of which is going to hit any particular statement. So, you could see something like this:

// Note that instance == null as we've never called the lazy getInstance() before.

Thread1: if (instance == null)
Thread2: if (instance == null) // both tests pass - DANGER
Thread1:     instance = new MySingleton();
Thread2:     instance = new MySingleton(); // Note - you just called the constructor twice
Thread1: return instance; // Two singletons were actually created 
Thread2: return instance; // Any side-effects in the constructor were called twice

The problem illustrated in the if-null test is called a race condition. You can't know who's going to what statement when. As a result, it's like both threads are racing each other to a cliff.

If you look at the same sort of examination of my example with both threads still hitting getInstance() at the same moment, you see something like this:

Thread1: return instance;
Thread2: return instance;

Simplistic, yes, but that's my point. The object was constructed once, long ago, and the threads can count on its value being consistent. No race exists.

NOTE: you still have to worry about the contents of the constructor for OtherObject. The lesson there is: concurrency is hard. If you're making your constructor thread safe (which you should), make sure that the author of OtherObject is doing you the same courtesy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文