简体   繁体   English

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

[英]Why is Class.newInstance() “evil”?

Ryan Delucchi asked here in comment #3 to Tom Hawtin 's answer: 瑞安DELUCCHI这里的评论#3 汤姆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? 那么,为什么它是邪恶的?

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. 请注意,此方法传播由Nullary构造函数抛出的任何异常,包括已检查的异常。 Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler. 使用此方法可以有效地绕过编译时异常检查,否则将由编译器执行。 The Constructor.newInstance method avoids this problem by wrapping any exception thrown by the constructor in a (checked) InvocationTargetException . Constructor.newInstance方法通过在(已检查的) InvocationTargetException包装构造函数抛出的任何异常来避免此问题。

In other words, it can defeat the checked exceptions system. 换句话说,它可以击败已检查的例外系统。

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(),则可能无法在重构期间找到该用法,并且在编译时此问题不会显现。

I don't know why no one provided a simple example based explanation to this, as compared to Constructor::newInstance for example, since finally Class::newInstance was 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 IOException being thrown - problem is that your code does not handle it, neither handle 1 nor handle 2 will catch it. 调用此方法将导致抛出IOException - 问题是您的代码无法处理它, handle 1handle 2都不会捕获它。

In contrast when doing it via a Constructor : 相比之下,通过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::newInstance bypasses the exception handling - which you really don't want. 实际上, Class::newInstance绕过了异常处理 - 你真的不想要它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM