是否可以将检索到的Class对象(通过反射)转换为接口?

时间:2012-05-13 14:57:46

标签: java android reflection

我的工作区中有3个项目--A,B和C,这是一个Android lib项目。

  1. A包含名为Atest
  2. 的活动
  3. B包含一个名为Btest的类,它实现了接口I
  4. C包含I接口。
  5. A和B都安装在我的Android设备上。 在Atest运行时期间,我正在执行下一个代码:

    Context otherContext = createPackageContext("com.package.b",
                    CONTEXT_INCLUDE_CODE | CONTEXT_IGNORE_SECURITY);
    ClassLoader loader = otherContext.getClassLoader();
    Class<?> btest = Class.forName("com.package.b.BTest", true, loader);
    

    现在这是我的问题 - 有没有办法在I运行上下文中将btest转换为A

    我尝试了许多明显的(以及一些不那么明显的)技巧,但对我来说没有任何效果。我当然可以探索btest的方法和接口,调用它的方法等等。但我根本无法将它转换为I,尽管A和B都引用了lib中完全相同的I接口-project C。

    提前致谢!

    P.S。

    请注意,我将其投射到界面中,而不是放入对象中,因此我认为在这种情况下不同的ClassLoader不是原因。

3 个答案:

答案 0 :(得分:1)

你的问题非常不明确,所以我不得不猜测你的意思。

首先,Java中没有Interface类,所以你不能这样说:

    Interface<?> i = // some magic transformation of btest

所以,我认为你在谈论向界面投射com.package.b.BTest的实例(让我们称之为......)com.package.i.I

  • 如果BtestI都已静态加载,则(I) bTestInstance可以完成此任务。

  • 如果动态加载BtestBtest实施I,则以下内容应该有效:

        Class<?> btestCls = Class.forName("com.package.b.BTest", true, loader);
        // This will work, because I has to be on the classpath of 'loader'
        // for the previous load to work ...
        Class<?> iCls = Class.forName("com.package.i.I", true, loader);
    
        Object btest = // create a BTest instance reflectively
        Object i = iCls.cast(btest);
    

    问题当然是因为您的代码已动态加载BTestI,所以无法编写静态类型为BTestI的变量。所以演员阵容没有任何实际意义,除了作为断言BTest实施I的圆周方式。

另一种可能性是你在讨论如何转换类对象。但鉴于您必须使用通配符作为Class的类型参数,这没有任何意义。


重申一下,如果I静态链接到您的代码中,那么您可以这样做:

Object btest = // create or retrieve the instance reflectively
I i = (I) btest;

如果I没有静态链接到您的代码中,那么您(显然)不能在上面声明I i,并且您必须对btest实例中的所有操作使用反射。你不能反思地“做”静态打字。周期。

答案 1 :(得分:1)

因为您在运行时执行所有此动态加载,所以不构造虚拟方法表及其关联的vpointers。因此,运行时无法动态地将对接口方法的调用分派给适当加载的实现。你必须使用反射。

答案 2 :(得分:0)

接口I必须位于类路径上(或者可由运行时加载),否则您将获得运行时异常。反思不会让你避免这个问题。