| 維度 | new 關鍵字 | Class.newInstance() / Constructor.newInstance() |
|---|---|---|
| 類型 | 關鍵字 (語法層面) | 方法 (反射 API) |
| 類型安全 | 強類型,編譯期檢查 | 弱類型,執行期檢查 |
| 建構子支援 | 任意 public 建構子 | 僅無參建構子 (Class.newInstance())任意建構子 ( Constructor.newInstance()) |
| 效能 | 高 (JIT 內聯優化) | 低 (反射解析、存取檢查、裝箱/拆箱) |
| 類載入時機 | 首次主動使用時 (可能早於 new) | 需先 Class.forName() 觸發載入+連結 |
| 異常處理 | 編譯期強制處理受檢異常 | 拋出 InvocationTargetException 包裝真實異常 |
new 指令流程<init> 建構子JVM 內建指令,JIT 可深度優化(逃逸分析、標量替換、鎖消除)。
newInstance() 流程Class.forName() → 啟動類載入器 → 載入、連結、初始化類Constructor)setAccessible(true) 繞過存取檢查 (可選)涉及 MethodAccessor 委派機制(委派 → 原生 → 動態生成字節碼),首次調用極慢,熱度達標後 JIT 可內聯優化。
經典場景:框架/容器根據配置動態建立實例,不依賴具體類。
<!-- config.xml -->
<bean id="paymentProcessor" class="com.acme.PayPalProcessor"/>
// 框架代碼
String className = config.getAttribute("class"); // 從 XML 讀取
Class> clazz = Class.forName(className);
PaymentProcessor processor = (PaymentProcessor) clazz.getDeclaredConstructor().newInstance();
優勢:
Constructor.newInstance() 取代 Class.newInstance()Class.newInstance() 自 JDK 9 標記棄用,原因:
InstantiationException/IllegalAccessException,除錯困難正確寫法:
public static T newInstance(Class clazz, Object... args) {
try {
Constructor ctor = clazz.getDeclaredConstructor(getParameterTypes(args));
ctor.setAccessible(true); // 僅當必要時
return ctor.newInstance(args);
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("反射實例化失敗: " + clazz, e);
}
}
MethodHandles.lookup().findConstructor(),更接近 JVM 指令,JIT 優化更好。new、工廠方法、Builder 模式。new (最快、最安全、可讀性最佳)Constructor.newInstance() + 快取理解底層機制,才能在架構決策時權衡「解耦彈性」與「執行效能」的取捨。