Установка значения в объект с помощью отражения - PullRequest
5 голосов
/ 28 апреля 2010

У меня есть объект, который имеет много атрибутов , каждый из которых имеет свой метод получения и установки. Каждый атрибут имеет не примитивный тип, который я не знаю во время выполнения.

Например, вот что у меня есть:

public class a{

    private typeA attr1;
    private typeB attr2;

    public typeA getAttr1(){ return attr1; }
    public typeB getAttr2(){ return attr2; }

    public void setAttr1(typeA at){ attr1 = at; }
    public void setAttr2(typeB at){ attr2 = at; }
}

public class typeA{
    public typeA(){
        // doesn't matter
    }
}

public class typeB{
    public typeB(){
        // doesn't matter
    }
}

Итак, используя отражение, я получил метод установки для атрибута. Установка значения стандартным способом выглядит примерно так:

a test = new a();
a.setAttr1(new typeA());

Но как я могу сделать это, используя отражение? Я уже получил метод setAttr1 () , использующий отражение, но я не знаю, как создать новый объект typeA для вставки в установщик.

Ответы [ 4 ]

11 голосов
/ 28 апреля 2010

Использование Class#newInstance().

Class<TypeA> cls = TypeA.class;
TypeA typeA = cls.newInstance();

Или, в вашем конкретном случае, когда вам нужно определить тип параметра метода:

Class<?> cls = setterMethod.getParameterTypes()[0];
Object value = cls.newInstance();
setterMethod.invoke(bean, value);

Подробнее об отражении вы можете узнать в Sun уроке по предмету . Тем не менее, имена классов должны начинаться с заглавной буквы. Я исправил это в приведенном выше примере.

Кстати, вместо того, чтобы изобретать колесо отражения Javabean, вы можете найти один из упомянутых здесь инструментов .

3 голосов
/ 29 апреля 2010

Используйте метод getDeclaredFields() в объекте Class, чтобы получить все поля, затем используйте field.set(classInstance, value), чтобы установить значение поля в экземпляре. Примечание. Возможно, вам придется установить флаг доступности в поле на true, если поле является закрытым. Нет необходимости полагаться на методы установки.

2 голосов
/ 29 апреля 2010

Я столкнулся с этим на некоторых вещах, которые я делал. Мой общий вывод состоял в том, что всякий раз, когда я чувствовал, что мне нужен класс с кучей полей, я делал это неправильно. Вот мой мыслительный процесс:

Проблема: - мне нужно большое количество полей для хранения этих данных - Все эти поля требуют огромного количества шаблонов

Решение:

  • использовать отражение, чтобы уменьшить шаблон <"вы здесь" </li>
  • Используйте метаданные, чтобы указать, как должны использоваться поля

Новые проблемы:

  • Отражение трудно понять, когда кто-то новый смотрит на код
  • Как только вы переходите к мета-методу, чтобы исключить дополнительные шаблоны, поля часто не упоминаются в коде, кроме как через метаданные - почему они являются полями?
  • Указание метаданных в коде довольно быстро становится громоздким (кстати, самый простой способ - массив строк)

Решение: начать хранение данных в коллекции и указать метаданные во внешнем файле данных

Новая проблема: ошибки становятся трудно найти

Тщательно относитесь к проверке ошибок и очень внимательно относитесь к сообщениям об ошибках. Убедитесь, что все другие программисты, которые могут использовать ваш код, прочитали сообщения об ошибках. Попытайтесь указать, когда метаданные отсутствуют или неправильны, и как программист должен обновить метаданные, включая местоположение файла метаданных.

Проблема: нет безопасности типа

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

Проблема: метаданные нужны многократно в течение жизни объекта

Вместо того, чтобы искать его по имени при каждом его использовании, я бы сначала проанализировал метаданные и поместил их в объект (назовите его IntHolder). Этот держатель окажется в хеш-таблице и будет содержать текущее значение, а также ссылку на проанализированные метаданные.

Пример

Вот как мои метаданные заканчиваются для одного поля таблицы стилей:

FieldName:     Age
FieldType      Integer
ScreenBinding: AgeTextField
DBBinding:     User.age
Validation:    IntRange(0, 120); "Age is out of range"

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

Когда вам нужно использовать, используйте getInt ("Age") и setInt ("Age", 12) вместо getAge () и setAge (12) - немного более многословно, но на самом деле это не проблема.

Если это проблема, вы можете создать вспомогательные методы getAge / setAge, и вам никогда не нужно будет знать, что это не поле, но это снова начинает накапливаться на шаблоне.

FieldType: указывает, как он хранится, и позволяет реализовать проверку типов.

ScreenBinding и DBBinding используются для копирования значения в и из других систем. Я также использовал этот тип механизма для передачи данных с сервера на клиент и обратно.

Самое интересное - Валидация. При извлечении данных с экрана они могут быть переданы в валидатор очень прогрессивным способом. Тот же валидатор может быть использован перед фиксацией в БД.

Валидаторы могут делать гораздо больше, они могут действовать как триггеры (если значение изменяется, делайте это) или действия (когда пользователь отправляет экран, делайте это). Это простые объекты со способностью принимать значение (через интерфейс) - они могут быть настолько гибкими или мощными, насколько вам угодно, но не привязаны напрямую к какому-либо объекту, кроме как через метаданные.

Единственная проблема этого подхода в том, что вы должны относиться к типу программиста, который любит писать осветительные приборы, а не подвержен ошибкам. (Да, я нахожу, что количество времени примерно одинаково, но я, как правило, становлюсь очень медленным, когда мне приходится внедрять шаблон)

После того, как я сделал это несколько раз, я действительно люблю шаблон, но его сложно реализовать. В следующий раз, когда я сделаю это, я попытаюсь превратить это в библиотеку какого-то типа.

1 голос
/ 28 апреля 2010

Если вы хотите установить «свежий» объект в каждом установщике вашего класса, вы обычно можете сделать это, получив Method, для каждого метода вы получите Class аргументов с getParameterTypes(), для каждый класс, который вы вызываете Class.newInstance() ... и скрещиваете пальцы (это должно нарушаться примитивными типами - я сомневаюсь, что Java здесь выполняет автобокс). Вы всегда можете спросить, является ли параметр ограничивающим вызовом isPrimitive ()

Почему вы хотите установить "пустые" экземпляры для примитивных полей класса? Они уже инициализированы. Вы хотите "сбросить" их?

...