在运行时使用反射来实例化未知类的对象的正确方法是什么?

时间:2011-10-08 16:35:35

标签: java reflection

我正在开发一个Configuration Loader类,这样我就可以通过外部文本文件(config.txt)更改程序的参数,而不必在每次更改时重新编译我的代码。

有人建议我使用Java的Reflection来做这件事,但我对如何实际实现这一点感到困惑。

我已经能够从我的文本文件中成功提取其构造函数的类名和参数,但是如何从此实例化到实例化对象?

这是我到目前为止的方法:

public void loadObject(String classString, HashMap hm)
  {
  String className = props.getProperty(classString);
  Class c = Class.forName(className);
  }

classString是一个包含类名称的字符串,hm是一个hashmap,其中类的构造函数参数映射到它们的预期值。

即,对于class Foo (int xPos, float yPos),“xPos”将映射到预期int的字符串,“yPos”映射到预期float的字符串。我希望能够返回new Foo(hm.get"xPos".toInt, hm.get"yPost".toFloat),但我不确定如何动态使用这样的构造函数(问题是,有多个可能的类 - 也许它是一个{ {1}}而不是bar,例如)。

我知道可以基于classString做一个基于if / else的操作,并且在识别它之后简单地调用正确的构造函数,但我希望创建一个不需要每次都重写的更可扩展的代码我在课程中添加了一个新课程。

所有可能的对象都从单个父对象继承。

3 个答案:

答案 0 :(得分:14)

您可以使用Class.getConstructor(Class<?>... parameterTypes)来获取对Constructor.newInstance(Object... initargs)后面的构造函数的引用。

但是我建议看一下依赖注入框架,例如Spring或Guice,因为它听起来像你正在创建的是他们所做的基本版本。

请求扩展此答案:

Class c = Class.forName(name);
Constructor ctor = c.getConstructor(Integer.class, Integer.class);
Integer param1 = hm.get("xPos") ...;
Integer param2 = hm.get("yPos") ...;
Object instanceOfTheClass = ctor.newInstance(param1, param2);

当然,代替param1param2,您将根据输入文件中的内容创建一个参数数组(getConstructor()的参数也是如此)等。

答案 1 :(得分:3)

以下是从程序参数中执行此操作的示例:

import java.lang.reflect.Constructor;
import java.util.*;

public class InstantiateWithReflectionIncludingArgs {
    public static void main(String[] args) throws Exception {
        String className = args[0];
        List<Object> argList = new ArrayList<Object>();
        if (args.length > 1) {
            argList.addAll(Arrays.asList(args).subList(1, args.length));
        }
        Class c = Class.forName(className);
        List<Class<?>> argTypes = new ArrayList<Class<?>>();
        for (Object arg : argList) {
            argTypes.add(arg.getClass());
        }
        Constructor constructor = c.getConstructor(
            argTypes.toArray(new Class<?>[argTypes.size()]));
        Object o = constructor.newInstance(
            argList.toArray(new Object[argList.size()]));
        System.out.println("Created a " + o.getClass() + ": " + o);
    }
}

当然,argList在这种情况下只能使用字符串,因为它们是从String[]中提取的,但您可以添加任何类型的参数。请注意,构造函数args是位置的,而不是命名的,因此地图中的名称对您没有多大帮助。他们需要处于正确的顺序。

尝试运行它并将“java.util.Date”作为参数传递。

答案 2 :(得分:1)

Class<?> clazz = MyClass.class;
Constructor<?> ctor = clazz.getConstructor( /* Array of Classes the constructor takes */);
ctor.newInstance( /* arguments the constructor takes */ );