Java 为什么Class.newInstance()是;邪恶;?

Java 为什么Class.newInstance()是;邪恶;?,java,constructor,runtime,instantiation,Java,Constructor,Runtime,Instantiation,在对的回答的第3条评论中被问到: 为什么Class.newInstance()是“邪恶的” 这是对代码示例的响应: // Avoid Class.newInstance, for it is evil. Constructor<? extends Runnable> ctor = runClass.getConstructor(); Runnable doRun = ctor.newInstance(); //避免Class.newInstance,因为它是邪恶的。 构造函数Jav

在对的回答的第3条评论中被问到:

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

这是对代码示例的响应:

// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
//避免Class.newInstance,因为它是邪恶的。

构造函数Java API文档解释了原因():

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

换句话说,它可以击败已检查的异常系统。

还有一个原因:

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


如果您不显式使用构造函数,而是使用Class.newInstance(),那么在重构过程中可能找不到该用法,并且这个问题在编译时不会表现出来。

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

假设您有一个非常简单的类(不管它是否损坏):

你试着通过反射来创建它的一个实例。第一个
类::newInstance

    Class<Foo> clazz = ...

    try {
        clazz.newInstance();
    } catch (InstantiationException e) {
        // handle 1
    } catch (IllegalAccessException e) {
        // handle 2
    }
句柄3将被调用,因此您将处理它


实际上,
Class::newInstance
绕过了异常处理——这是您真正不想要的。

实际上看到了这个问题的答案:可以这样说反射的各种用途。。。不仅仅是Class.newInstance()。所以这实际上是一个普遍的观察结果,即“反射破坏了编译时检查”。。。这通常是反思的重点。现在的孩子们,哦,是的,他们到处乱说“邪恶”这个词,但他们甚至从未见过COBOL或FORTRAN程序!你想要“邪恶”看看有20年历史的FORTRAN程序,它是由tinker's在一个模拟背景下从一个项目传递到另一个项目的,没有CS的影响!现在“邪恶”也看到了,这是反射的本质。。。一点也不特定于构造函数。newInstance()。@Ryan:那不是真的;所有其他基于反射的调用方法都会抛出一个选中的异常,名为
InvocationTargetException
,该异常封装了被调用方法抛出的任何可丢弃项
Class.newInstance
不会这样做——它将直接抛出选中的异常。缺点是javac也不允许您尝试捕获这些异常,因为
Class.newInstance
没有声明抛出它们。这也是使用反射的一般方法。
    Class<Foo> clazz = ...

    try {
        clazz.newInstance();
    } catch (InstantiationException e) {
        // handle 1
    } catch (IllegalAccessException e) {
        // handle 2
    }
    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();
    }