[英]Why InvokeVirtual used instead of InvokeSpecial when calling class.NewInstance()?
[英]Why is Class.newInstance() “evil”?
瑞安DELUCCHI問這里的評論#3 湯姆Hawtin的回答是:
為什么Class.newInstance()“邪惡”?
這是為了響應代碼示例:
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
那么,為什么它是邪惡的?
Java API文檔解釋了原因( http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance() ):
請注意,此方法傳播由Nullary構造函數拋出的任何異常,包括已檢查的異常。 使用此方法可以有效地繞過編譯時異常檢查,否則將由編譯器執行。
Constructor.newInstance
方法通過在(已檢查的)InvocationTargetException
包裝構造函數拋出的任何異常來避免此問題。
換句話說,它可以擊敗已檢查的例外系統。
還有一個原因:
現代IDE允許您查找類用法 - 如果您和您的IDE知道哪些代碼正在使用您計划更改的類,則它在重構期間會有所幫助。
如果不明確使用構造函數,而是使用Class.newInstance(),則可能無法在重構期間找到該用法,並且在編譯時此問題不會顯現。
我不知道為什么沒有人提供一個簡單的基於示例的解釋,例如與Constructor::newInstance
相比,因為最終 Class::newInstance
自java-9以來已被棄用。
假設你有這個非常簡單的類(無論它是否被破壞):
static class Foo {
public Foo() throws IOException {
throw new IOException();
}
}
並且您嘗試通過反射創建它的實例。 Class::newInstance
:
Class<Foo> clazz = ...
try {
clazz.newInstance();
} catch (InstantiationException e) {
// handle 1
} catch (IllegalAccessException e) {
// handle 2
}
調用此方法將導致拋出IOException
- 問題是您的代碼無法處理它, handle 1
和handle 2
都不會捕獲它。
相比之下,通過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();
}
將調用句柄3,因此您將處理它。
實際上, Class::newInstance
繞過了異常處理 - 你真的不想要它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.