Object mapperObj = Class.forName(mapperClassName).newInstance();
MapperInterface mapper = (MapperInterface) mapperObj; // 拋 ClassCastException
mapperObj.getClass().getClassLoader() → sun.misc.Launcher$AppClassLoader (System ClassLoader)MapperInterface.class.getClassLoader() → WebContainerClassLoader (App ClassLoader,Web 容器自定義)JVM 載入類規則:同一個類必須由同一 ClassLoader 定義才視為同一類型。此處介面與實現類被不同層級 ClassLoader 定義,雖名稱相同但非同一 Class 對象,強轉失敗。instanceof 也會返回 false。
java.ext.dirs)CLASSPATH)雙親委派:載入時向上委派,定義時向下隔離。
無法變更實現類 ClassLoader,且實例已建立。改用反射檢查介面並調用方法:
Object mapper = Class.forName(mapperClassName).newInstance();
boolean implementsInterface = false;
for (Class> iface : mapper.getClass().getInterfaces()) {
if (iface.getName().equals(MapperInterface.class.getName())) {
implementsInterface = true; break;
}
}
if (implementsInterface) {
Method method = mapper.getClass().getMethod("mapFunction", String.class, HttpServletRequest.class);
Object result = method.invoke(mapper, event.getServletClassName(), req);
// 處理 result...
}
ClassLoader 隔離是容器模組化的基石,但也帶來類身份陷阱。反射繞過編譯期類型檢查,是解決跨 ClassLoader 呼叫的常用應急手段,但犧牲了型別安全與效能,架構設計階段應盡量避免跨層級共享介面類。