首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android DexClassLoader 加載插件 Jar 類轉型失敗:ClassLoader 隔離導致同接口不同類對象

     編輯:程式設計綜合問答

錯誤現象

ClassCastException: com.example.interf.JarLoader cannot be cast to com.example.impl.ILoader,接口類名相同但加載器不同。

根因

  • 宿主 App 用 **系統/應用 ClassLoader** 加載 `ILoader` 接口類。
  • 插件 Jar 由 `DexClassLoader` 加載,內部**又包含一份 `ILoader.class`**。
  • JVM 判斷類身份:`完整類名 + ClassLoader 實例`。兩個 ClassLoader 加載同名類 → **兩個不同的 Class 對象**,無法轉型。

解決方案

方案一:接口類不打包進插件(推薦)

  1. 插件構建時**排除接口包**(`com.example.interf`),只打包實現類。
  2. 宿主與插件共用同一份接口 Class 對象(由宿主 ClassLoader 加載)。
  3. Gradle 配置:jar { exclude 'com/example/interf/**' }。

方案二:父優先委派模式

public class PluginClassLoader extends DexClassLoader {
    public PluginClassLoader(...) { super(...); }
    @Override
    protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
        if (name.startsWith("com.example.interf.")) // 接口包
            return getParent().loadClass(name);     // 委派給宿主加載器
        return super.loadClass(name, resolve);
    }
}

方案三:統一用 PathClassLoader(系統應用)

若插件已安裝為獨立 APK,宿主用 `context.createPackageContext(pkg, CONTEXT_INCLUDE_CODE).getClassLoader()` 直接獲取插件 ClassLoader,避免雙份加載。

最佳實踐

  • **接口/基類放宿主**,插件只含實現,構建時剔除接口字節碼。
  • 使用成熟插件框架,已處理 ClassLoader 隔離問題。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved