Java:如何在单例中重现Legen...dary ClassNotFoundException?

发布于 2024-12-06 06:32:08 字数 832 浏览 1 评论 0原文

在我的上一次面试中,我被问到一个关于 java 中所有 Singleton 实现的标准问题。他们都是多么糟糕。

有人告诉我,即使静态初始化也很糟糕,因为构造函数中可能会出现未经检查的异常:

public class Singleton {
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
    private Singleton() {
       throw new RuntimeException("Wow... Exception in Singleton constructor...");
    }
}

他们还告诉我,异常将是“ClassNotFoundException”,因此在实际应用程序中很难找到问题。

我试图获得该异常:

public static void main(String[] args) {
    new Thread(new Runnable(){
            public void run() {
                Singleton.getInstance();
            }
        }).start();
}

但我得到的唯一结果是 ExceptionInInitializerError ...

我在谷歌上搜索了该异常以及我发现的所有地方 - 他们都谈到了我在面试中被告知的同一问题。没有任何关于“实施”的内容=)

感谢您的关注。

On my last interview I was asked a standard question about all Singleton implementations in java. And how bad they all are.

And I was told that even the static initialization is bad because of the probability of unchecked exception in constructor:

public class Singleton {
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
    private Singleton() {
       throw new RuntimeException("Wow... Exception in Singleton constructor...");
    }
}

And they also told me that the Exception is gonna be "ClassNotFoundException" so it would be extremely hard to find the problem in real app.

I tried to get that Exception:

public static void main(String[] args) {
    new Thread(new Runnable(){
            public void run() {
                Singleton.getInstance();
            }
        }).start();
}

But the onlything I get is ExceptionInInitializerError...

I googled about that exception and everywhere I found - they all talked about the same problem I was told on my interview. Nothing about the "implementation"=)

Thanks for your attention.

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

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

发布评论

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

评论(4

月下凄凉 2024-12-13 06:32:08

有时你在面试中会遇到奇怪的问题,你应该时刻准备好意想不到的事情。 ;)

您使用的任何技术都有优点和缺点。您必须知道何时是使用它们的好时机、可能出现的问题以及如何解决它们。

重要的是要记住,几乎每个问题都有解决方案或解决方法。

在我的上次面试中,我被问到一个关于 Java 中所有单例实现的标准问题。他们都有多糟糕。

听起来不像是一个问题,更像是一场宗教辩论。

有人告诉我,即使静态初始化也很糟糕,因为构造函数中可能会出现未经检查的异常:

Siderman IV:蜘蛛侠 vs Singleton 和静态初始化程序。 (坏人;)

抛出 new RuntimeException(“哇...单例构造函数中出现异常...”);

这是一个坏主意,所以不要这样做。事实上它甚至不会编译。 Java 6 中的编译器报告。

initializer must be able to complete normally

他们还告诉我,异常将是“ClassNotFoundException”,因此在实际应用程序中很难找到问题。

您会收到 ExceptionInInitializerError ,其中包含导致问题的异常原因。除了必须读取嵌套异常之外,它并不那么棘手。

static class Inner {
    static {
        Integer.parseInt(null);
    }
}

public static void main(String... args) {
    try {
        new Inner();
    } catch (Throwable e) {
        e.printStackTrace();
    }
    new Inner();
}

Exception in thread "main" java.lang.ExceptionInInitializerError
at Main.main(Main.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:417)
at java.lang.Integer.parseInt(Integer.java:499)
at Main$Inner.<clinit>(Main.java:8)

Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class Main$Inner
at Main.main(Main.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

是第一次发生,此后如果您尝试再次使用该类,您会收到 NoClassDefFoundError 错误。

过去,当您尝试使用反射访问类时,如果失败,您会收到 ClassNotFoundException(没有实际发生情况的详细信息),但现在情况已不再如此。

Sometimes you get strange questions in interviews, you should always expect the unexpected. ;)

Any technique you use has positives and minuses. You have to know when is a good time to use them and what the problem might be and how to work around them.

The important thing to remember that almost every problem has a solution or a work around.

On my last interview I was asked a standard question about all Singleton implementations in java. And how bad they all are.

Sounds less like a question, more like a religious debate.

And I was told that even the static initialization is bad because of the probability of unchecked exception in constructor:

Siderman IV: Spider man vs Singleton and the Static Initialiser. (the bad guys ;)

throw new RuntimeException("Wow... Exception in Singleton constructor...");

That is a bad idea, so don't do that. In fact it won't even compile. The compiler in Java 6 reports.

initializer must be able to complete normally

And they also told me that the Exception is gonna be "ClassNotFoundException" so it would be extremely hard to find the problem in real app.

You get a ExceptionInInitializerError with a cause of the exception which caused the problem. Apart from having to read the nested exception its not that tricky.

static class Inner {
    static {
        Integer.parseInt(null);
    }
}

public static void main(String... args) {
    try {
        new Inner();
    } catch (Throwable e) {
        e.printStackTrace();
    }
    new Inner();
}

prints

Exception in thread "main" java.lang.ExceptionInInitializerError
at Main.main(Main.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:417)
at java.lang.Integer.parseInt(Integer.java:499)
at Main$Inner.<clinit>(Main.java:8)

Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class Main$Inner
at Main.main(Main.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

This happens the first time, after that you get NoClassDefFoundError if you try to use the class again.

It used to be that when you tried to access a class using reflections, and it failed you got a ClassNotFoundException (with no details as to what really happens) However this is no longer the case.

Oo萌小芽oO 2024-12-13 06:32:08

我认为,我认为您永远不会从这样的构造中得到 ClassNotFoundException 。类加载器不会加载该类失败,但会无法初始化它。根据 Javadoc,ExceptionInInitializerError 是正确的:

ExceptionInInitializerError“表示出现意外异常
发生在静态初始化程序中。 ExceptionInInitializerError 是
抛出以表明在评估期间发生异常
静态初始值设定项或静态变量的初始值设定项。”,其中
正是您的情况。

旁注:根据 Joshua Bloch(部分 Java API 和《Effective Java》一书的作者)的说法,在 Java 中实现单例的最纯粹的方法是单例枚举模式 (http://stackoverflow.com/questions/) 70689/在 Java 中实现单例模式的有效方法)。

无论如何,未经检查的异常都可能发生在任何类的构造函数中,因此在我看来,这种可能性不足以成为不在 Java 中使用静态初始化单例模式的理由。

Imo, I don't think you'll ever get a ClassNotFoundException out of a construction like that. The classloader will not fail to load that class, but will fail to initialize it. The ExceptionInInitializerError is correct, according to Javadoc:

ExceptionInInitializerError "signals that an unexpected exception has
occurred in a static initializer. An ExceptionInInitializerError is
thrown to indicate that an exception occurred during evaluation of a
static initializer or the initializer for a static variable.", which
is exactly your case.

Side note: the most purist way of implementing a singleton in Java is, according to Joshua Bloch (author of part of the Java API and the book "Effective Java") the Singleton Enum Pattern (http://stackoverflow.com/questions/70689/efficient-way-to-implement-singleton-pattern-in-java).

In any case, unchecked exceptions can potentially happen in the constructor of any class, so in my opinion this possibility is not a reason enough to not use the Static Initialization Singleton Pattern in Java.

写下不归期 2024-12-13 06:32:08

如果您说由于从 Singleton 类的 ctr 抛出 RuntimeException ,将抛出 ClassNotFoundException - 那么这不是正确 - CNFEx 是运行时无法找到要加载的类的结果 - 首先调用 ctr 代码的事实足以排除 CNFEx 的可能性。

If you saying that on account of a RuntimeException being thrown from the ctr of the Singleton class , a ClassNotFoundException will be throw - then that is not correct - CNFEx is a results of the runtime failing to locate the class to load - the fact that the ctr code is called at the first place is evidence enough to rule out CNFEx.

逐鹿 2024-12-13 06:32:08

这很简单。您的构造函数应该调用一些第三方库。例如log4j。在类路径中使用 log4j.jar 进行编译,然后运行。您将收到 ClassDefNotFoundError。如果您确实需要 ClassNotFoundException 使用动态类加载启动某个类: Class.forName("MyNotExistingClass")

无论如何,我认为您的面试官是错误的。静态初始化的问题是不可能出现 RunTimeExceptions 的:您将在应用程序的 STDERR 上看到它们。问题是它们在需要实际对象之前运行,而经典单例的延迟初始化仅在真正要使用实例时运行。

It is very simple. Your constructor should call some third party library. For example log4j. Compile it with log4j.jar in classpath and then run without. You will get ClassDefNotFoundError. If you really need ClassNotFoundException initiate some class using dynamic class loading: Class.forName("MyNotExistingClass")

Anyway, I think that your interviewer is wrong. The problem with static initialization is not possible RunTimeExceptions: you will see them on STDERR of your application. The problem is that they run before the real objects are needed while lazy initialization of classic singleton is running only when the instance is really going to be used.

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