【问题标题】:dynamically cast and invoke in Java在 Java 中动态转换和调用
【发布时间】:2013-04-07 16:13:45
【问题描述】:

我在我的 WebApp 中使用了一些 Reflexion。我想做的是在做类型案例之后动态调用一个方法——这在编译时也不知道

这是我的代码结构:

            Controller (Interface with one method called 'execute()')
                   |
                   |
                  \|/
             BaseController (Abstract Class with 1 abstr method called 'execute()')
              /         \
             /          _\|
            /            GetCarController extends BaseController
          |/_
         AddCarController extends BaseController

现在我有了使用上述结构的代码:

  BaseController baseContr;

   Properties prop = new Properties();
   prop.load("some inputstream to config.properties");

    Constructor cons = Class.forName( prop.getProperty( keyProperty ) ).
    getConstructor( Class.forName( prop.getProperty( keyProperty ) ).getClass() );// keyProperty is some input string from user
   ( ( XXXXXX )cons.newInstance ( new Car(....) )  ).execute();

您看到XXXXXX 实际上是我想要一种动态放置类型转换的方法。此强制转换必须找到在 AddCarControllerGetCarController 中调用 execute() 方法的方法 我不想直接使用 BaseController 的任何一个实现来调用方法,而是有一种方法可以根据 prop.getProperty(keyProperty) 给出的内容进行转换...

【问题讨论】:

  • 你为什么不只是投射到界面?一旦你构建了实例,你就知道它实现了接口,你可以调用 execute,对吧?
  • “它不起作用”是永远、永远、永远足够的信息。接口中没有实现。接口的全部意义在于为调用者提供一些可以在不知道实现的情况下调用的东西。它真的会起作用。
  • 如果我有这样的事情:InterfaceLevel interf = newInstanceOfImplementation; interf.executeMethodInImplementation() 不能根据多态性规则工作。因为编译器必须知道在哪里可以找到实现类的方法
  • 你错了。编译并且工作得很好。编译器完全了解InstanceOfImplementation。看我的回答。
  • @kholofelo:不,确实没有,假设接口包含您要调用的方法的声明。我认为您误解了 Java 中一般的多态性和特定的接口是如何工作的。

标签: java dynamic reflection


【解决方案1】:

我认为您对多态性的工作方式感到困惑。如果您需要知道要转换到的确切类,那将完全破坏多态性的全部目的。

即使您转换为 BaseController - 或接口,正如 Jon Skeet 指出的那样,实际上更正确 - 实例仍将保持为 AddCarControllerGetCarController 实例,并调用 execute()在这种情况下,将调用AddCarController#execute()GetCarController#execute(),并且从不 BaseController#execute()

以下是有关此行为的示例:

class A {
    public void hello() {
        System.out.println("Hello from class A");
    }
}

class B extends A {

    @Override
    public void hello() {
        System.out.println("Hello from class B");
    }
}

public class Main {

    /**
     * @param args
     * @throws OperationNotSupportedException
     */
    public static void main(final String[] args) {
        final A a = new B();
        a.hello();
    }
}

按预期打印"Hello from class B"


编辑:使用反射和接口的更详细示例:

class A implements I {

    @Override
    public void hello() {
        System.out.println("Hello from class A");
    }
}

class B implements I {

    @Override
    public void hello() {
        System.out.println("Hello from class B");
    }
}

interface I {
    public void hello();
}

public class Main {

    /**
     * @param args
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws OperationNotSupportedException
     */
    public static void main(final String[] args) throws InstantiationException,
            IllegalAccessException, ClassNotFoundException {
        I i = (I) Class.forName("A").newInstance();
        i.hello();
        i = (I) Class.forName("B").newInstance();
        i.hello();
    }
}

【讨论】:

  • 是的,我可以理解,但问题是我想这样做:A a = (someImplementation) b 其中“someImplementation”是通过反射/动态发现的
  • 再一次,你不需要通过反射找到someImplementationb 应该是您已经通过反射创建的对象实例,并且应该是正确的类型。使用固定的someInterface 而不是someImplementation
  • 我很抱歉,但我认为是我无法正确解释我的问题......但是鉴于您上面的代码,如果我们不知道您的实现的类名怎么办,而是我们知道实现接口的任何东西都必须实现“execute”方法...所以我们不知道实现的名称是B...
  • 所以你得到了一个对象实例,你不知道它是什么类型,但你知道它实现了什么接口?我理解对了吗?如果是这样,则将其转换为界面。请参阅我的最后一个示例。
  • 是是是的,在这个:` i = (I) Class.forName("B").newInstance();`我们知道它的类型是I,但是在我的我什至不知道是I还是J
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多