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
Why is Class.newInstance() "evil"?
提问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.newInstance
method 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::newInstance
for example, since finallyClass::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 1
也handle 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::newInstance
bypasses the exception handling - which you really don't want.
有效地Class::newInstance
绕过异常处理 - 您真的不想要。