#java #аннотации #рефлексия
Помогите уяснить.
К примеру, одно из частных определений рефлексии говорит: "Рефлексия - это инструмент
с помощью которого можно узнать всю информацию о классе: имена методов, параметры,
поля, аннотации....".
У меня, как у новичка, возникает резонный вопрос, зачем мне эту информацию узнавать,
если классы, методы, поля и т.д. я пишу сам и всё про них знаю?
Понимаю, что используется рефлексия не для своих классов и т.д., но не могу найти
реальный пример, который был бы понятен новичку: в какой ситуации я столкнусь с тем,
что не буду знать имя класса, метода и т.д.?
То же самое с аннотациями: "...средство, позволяющее встраивать справочную информацию
в исходные файлы......". Ну встрою я её, ну а профит какой, что я в итоге с помощью
этого получу? Какие плюшки для разработчика появятся при наличии аннотаций? Как они
способны облегчить жизнь?
Ответы
Ответ 1
Рефлексия и аннотации позволяют решать задачи, который в иных случаях можно было
бы решить либо ручным монотонным кодированием, либо кодогенерацией.
И, конечно, когда они используются, то применяются не к конкретным классам, а с запасом,
даже к тем классам, которые вы напишете в будущем. Часто их используют в библиотечном
коде, который будет бродить между проектами и, соответственно, о классах тех проектов
вообще не знать ничего.
Несколько конкретных примеров:
Аннотации Hibernate
Hibernate — это ORM, то есть библиотека для удобного отображения баз данных на объектный
код. Часто в базе и в Java-коде применяются разные соглашения об именовании. Для того,
чтобы Hibernate понимал, какое поле куда копировать, применяют аннотации. Для таблицы:
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
Можно применить аннотации:
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@Id @GeneratedValue
@Column(name = "id")
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "salary")
private int salary;
public Employee() {}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Пример взят отсюда. Кратко, что здесь происходит: в базе данных поле называется,
например, first_name, а в Java-коде — firstName. Благодаря аннотациям при загрузке
записей из базы в объект Employee библиотека самостоятельно раскидает все поля как надо.
Компилятор Java
Компилятор также использует аннотации для дополнительных проверок или для изменения
своих настроек внутри отдельных методов. Смотрите аннотации @Override и @SuppressWarnings.
AndroidAnnotations
Проект http://androidannotations.org/ позволяет значительно упростить разработку
кода для Android, реализовав частые задачи, и обернув их в аннотации. Это как раз хороший
пример библиотечного кода, который будет работать в незнакомых проектах. Естественно,
для реализации этого кода активно применяется рефлексия. Пример «до аннотаций» и «после
аннотаций» приведён прямо на главной странице по ссылке выше.
Аспектно-ориентированное программирование
Про него много писать не буду, поскольку тема очень большая и новичку может быть
не сильно нужная. Но в целом АОП как раз об этом. Например, вы можете написать свои
классы, а потом озаботится проверкой прав доступа, навроде администратор может удалять
записи, а обычный пользователь — нет.
При классическом подходе вам придётся вносить однотипные изменения в большое количество
существующих классов, а потом не забывать делать это для новых. В АОП вы можете просто
придумать аннотации @Administrator, @User, @Moderator и расставить их у нужных классов
и методов. Это тоже монотонно, но всё равно гораздо проще.
Рефлексия без аннотаций
Рефлексия применяется ещё чаще, например, в разного рода шаблонизаторах и мапперах.
Шаблонизаторы позволяют вам использовать шаблоны писем, например, как этот:
Здравствуйте, %username%!
Напоминаем Вам, что вы задолжали нам крупную сумму денег в размере %amount%
рублей. Мы помним!
С уважением,
Коллекторское агентство «Солнышко»
Затем вы передаете шаблонизатору класс с полями username и amount и он самостоятельно
сформирует текст письма. Такую задачу без рефлексии не сделать.
Заключение
В целом, рефлексия и аннотации позволяют избавиться от так называемого monkey coding,
то есть от монотонного низкоуровнего кодирования.
Ответ 2
1) Dependency injection framework'и на рефлексии зачастую основаны
2) Вызывать методы по имени. Скажем, есть у вас на входе имя метода, вы можете его
вызвать так:
Method method = foo.getClass().getMethod("myMethod", null);
method.invoke(foo, null);
3) Тоже самое и для инстанциации классов. Мы делаем игру на Unity3d, тут, правда,
C#, но суть не меняется. У нас есть куча заклинаний. Список доступных заклинаний в
виде массива. Нам надо инстанциировать нужные классы по названию. Либо делать большой
switch блок с кучей case, либо вызвать всего 1 метод.
4) С помощью рефлексии можно достучаться до final и protected полей класса, если
необходимо. У меня была частая необходимость в этом, когда, к примеру, работал с Android.
Многие поля классов из SDK были скрыты, можно было достать и изменить их только с помощью
рефлексии.
P.S. но надо избегать использование рефлексии, где это возможно, так как она очень
медленная по природе