Java 为什么Class.newInstance()是;邪恶;?
在对的回答的第3条评论中被问到: 为什么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
// 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();
}