Java 为什么 Class.newInstance() 是“邪恶的”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/195321/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:10:48  来源:igfitidea点击:

Why is Class.newInstance() "evil"?

javaconstructorruntimeinstantiation

提问by Amir Arad

Ryan Delucchiasked herein comment #3 to Tom Hawtin's answer:

Ryan Delucchi在评论 #3 中对Tom Hawtin的回答提出质疑

why is Class.newInstance() "evil"?

为什么 Class.newInstance() 是“邪恶的”?

this in response to the code sample:

这是对代码示例的回应:

// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();

so, why is it Evil?

那么,为什么是邪恶的?

采纳答案by Chris Jester-Young

The Java API documentation explains why (http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance()):

Java API 文档解释了原因(http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance()):

Note that this method propagates any exception thrown by the nullary constructor, including a checked exception. Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler. The Constructor.newInstancemethod avoids this problem by wrapping any exception thrown by the constructor in a (checked) InvocationTargetException.

请注意,此方法会传播空构造函数抛出的任何异常,包括已检查的异常。使用此方法可以有效地绕过编译器否则会执行的编译时异常检查。该Constructor.newInstance方法通过将构造函数抛出的任何异常包装在 (checked) 中来避免这个问题InvocationTargetException

In other words, it can defeat the checked exceptions system.

换句话说,它可以打败受检异常系统。

回答by alexei.vidmich

One more reason:

还有一个原因:

Modern IDEs allow you to find class usages - it helps during refactoring, if you and your IDE know what code is using class that you plan to change.

现代 IDE 允许您查找类的用法 - 如果您和您的 IDE 知道哪些代码正在使用您计划更改的类,它会在重构过程中有所帮助。

When you don't do an explicit usage of the constructor, but use Class.newInstance() instead, you risk not to find that usage during refactoring and this problem will not manifest itself when you compile.

当您不显式使用构造函数,而是使用 Class.newInstance() 时,您可能会在重构期间找不到该用法,并且在编译时不会出现此问题。

回答by Eugene

I don't know why no one provided a simple example based explanation to this, as compared to Constructor::newInstancefor example, since finallyClass::newInstancewas deprecated since java-9.

我不知道为什么没有人对此提供一个简单的基于示例的解释,与Constructor::newInstance例如相比,因为最终Class::newInstance自 java-9以来已被弃用。

Suppose you have this very simple class (does not matter that it is broken):

假设你有这个非常简单的类(它坏了没关系):

static class Foo {
    public Foo() throws IOException {
        throw new IOException();
    }
}

And you try to create an instance of it via reflection. First Class::newInstance:

您尝试通过反射创建它的实例。第一Class::newInstance

    Class<Foo> clazz = ...

    try {
        clazz.newInstance();
    } catch (InstantiationException e) {
        // handle 1
    } catch (IllegalAccessException e) {
        // handle 2
    }

Calling this will result in a IOExceptionbeing thrown - problem is that your code does not handle it, neither handle 1nor handle 2will catch it.

调用它会导致IOException抛出 - 问题是您的代码不会处理它,handle 1handle 2不会捕获它。

In contrast when doing it via a Constructor:

相反,通过 a 执行此操作时Constructor

    Constructor<Foo> constructor = null;
    try {
        constructor = clazz.getConstructor();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }

    try {
        Foo foo = constructor.newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        System.out.println("handle 3 called");
        e.printStackTrace();
    }

that handle 3 will be called, thus you will handle it.

将调用句柄 3,因此您将处理它。

Effectively, Class::newInstancebypasses the exception handling - which you really don't want.

有效地Class::newInstance绕过异常处理 - 您真的不想要。