Как правильно использовать отражение для создания экземпляров объектов неизвестных классов во время выполнения? - PullRequest
8 голосов
/ 08 октября 2011

Я работаю над классом Configuration Loader, чтобы я мог изменять параметры своей программы через внешний текстовый файл (config.txt), а не перекомпилировать свой код при каждом внесенном мной изменении.

Было предложено, чтобы я использовал Reflection Java для этого, но я немного сбит с толку относительно того, как я мог бы на самом деле реализовать это.

Мне удалось успешно извлечь имя класса и аргументы для егоконструктор из моего текстового файла, но как мне перейти от этого к экземпляру объекта?

вот что у меня есть до сих пор моего метода:

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

classString - строка, содержащая имякласса, а hm - это хэш-карта, в которой параметры конструктора класса отображаются на их предполагаемые значения.

Т.е. для class Foo (int xPos, float yPos) xPos будет отображаться на строку предполагаемого целого числа, а "yPos"msgstr "отображает строку заданного числа с плавающей запятой.Я хочу, чтобы мог вернуть, new Foo(hm.get"xPos".toInt, hm.get"yPost".toFloat), но я не уверен, как динамически использовать такой конструктор (проблема в том, что существует несколько возможных классов - возможно, это bar вместоfoo, например).

Я знаю, что можно сделать if / else на основе classString и просто вызвать соответствующий конструктор после его идентификации таким образом, но я хочу создатьболее расширяемый код, который не нужно переписывать каждый раз, когда я добавляю в программу новый класс.

Все возможные объекты наследуются от одного родительского объекта.

Ответы [ 3 ]

14 голосов
/ 08 октября 2011

Вы бы использовали 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);

Конечно, вместо param1 и param2 вы бы создали массив аргументов на основе того, что было во входном файле (то же самое относится и к аргументам getConstructor()) и т. д.

3 голосов
/ 08 октября 2011

Вот пример того, как это делается из аргументов программы:

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[], но вы можете добавить аргументы любого типа. Обратите внимание, что аргументы конструктора являются позиционными, а не именованными, поэтому имена на карте не принесут вам большой пользы. Они должны быть в правильном порядке.

Попробуйте запустить его и передать в качестве аргумента "java.util.Date".

1 голос
/ 08 октября 2011
Class<?> clazz = MyClass.class;
Constructor<?> ctor = clazz.getConstructor( /* Array of Classes the constructor takes */);
ctor.newInstance( /* arguments the constructor takes */ );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...