在java中创建对象,而不需要在编译时知道Class

时间:2014-03-08 20:46:28

标签: java reflection

我有一个Java问题。我有一个配置文件,我读取并提取一些java类的路径,让我们说一个字符串的ArrayList(为方便起见,我将其称为 path2libs )。

我想通过迭代这个' path2libs '数组来动态地为每个类创建一个实例。我试过这样的事情:

Class clazz = Class.forName("test.Demo"); 
Demo demo = (Demo) clazz.newInstance();

但我不知道我会读什么课,所以我不能做适当的演员。

完成后,我想在每个对象上调用一个方法(在每种情况下都是相同的方法)。所有这些对象都基于一个接口,所以我知道它们的方法。

所以,基本上(总结一下)我有两个问题:)

  1. 创建理想的对象
  2. 在每个对象上调用方法

3 个答案:

答案 0 :(得分:2)

有很多问题。

首先,Class#newInstance()期望相应的类具有带有空参数列表的public构造函数。因此,您必须确保您要使用的所有类都具有该类。否则,您需要获得适当的Constructor,使其可访问,并提供适当的参数。

其次,你知道运行时所有类共享的界面吗?如果这样做,您可以将所有实例强制转换为该接口类型

InterfaceType interfaceInstance = (InterfaceType) clazz.newInstance();
interfaceInstance.interfaceMethod(/* arguments */);

如果你不这样做,你将不得不再次依靠反思。

您需要为相应的方法检索Method,并在方法的参数列表中提供每个参数的类型。

Method method = clazz.getDeclaredMethod("methodName" /*, possible parameter list types */);

然后,您可以在类的实例上调用该方法,再次提供适当的参数。

method.invoke(interfaceInstance /*, possible arguments */);

答案 1 :(得分:2)

  

“类无法转换为MyInterface”

这听起来像是在尝试将Class投射到这样的MyInterface后得到的编译器错误:

MyInterface mi = (MyInterface)Class.forName("test.Demo");

这是无效的,MyInterface不是Class,所以编译器可以确定转换永远不合法。相反,您应该将新实例强制转换为MyInterface。现在,有一种方法可以以更安全的方式执行此操作:

Class<?> wildCls = Class.forName("test.Demo");

Class<? extends MyInterface> miSubtypeCls = (
    wildCls.asSubclass(MyInterface.class)
);

MyInterface miSubtype = miSubtypeCls.newInstance();

这类似于非通用版本:

Class rawCls = Class.forName("test.Demo");

MyInterface miSubtype = (MyInterface)rawCls.newInstance();

但是,第一个版本不使用原始类型(不推荐使用),而asSubclass会在test.Demo未实现MyInterface时抛出ClassCastException。为此类场景提供了方法asSubclass

这是一个简短的演示:

package test;

public class HelloAsSubclass
implements Runnable {
    @Override
    public void run() {
        System.out.println("hello from Runnable implementation!");
    }

    public static void main(String[] args) {
        try {
            Class<?> wildCls = Class.forName("test.HelloAsSubclass");

            Class<? extends Runnable> rSubtypeCls = (
                wildCls.asSubclass(Runnable.class)
            );

            Runnable r = rSubtypeCls.newInstance();
            r.run();

        } catch(
            ClassNotFoundException |
            InstantiationException |
            IllegalAccessException ex
        ) {
            ex.printStackTrace();
        }
    }
}

当然也要确保你的子类型有一个公共的无参数构造函数(或者没有上面例子中的构造函数,并且基本上是相同的东西),这是newInstance的要求。否则,您需要将它们by getting a Constructor对象实例化。

答案 2 :(得分:0)

你做得很对。只是,您不会转换为Demo,而是转换为公共接口。毕竟,您希望对所有这些实例执行 common 。你想调用它们的方法。不知何故,你必须知道这些方法实际上是可用的。这就是接口的用途。