— Давай створимо зараз пару анотацій і використаємо їх.
Наприклад, ми пишемо ігровий рушій. Водночас у нашій грі дуже багато персонажів, які діляться на три категории: ельфи, охорона палацу і злодій.
Під час розробки гри можуть додаватися нові персонажі та, відповідно, змінюватися баланс гри. Тому було б дуже зручно приписати до кожного «класу персонажа» свою анотацію з описом його фізичних характеристик.
Тоді можна було б дуже просто симулювати бої між різними персонажами та/або швидко прорахувати баланс гри.
— Згоден, це слушна ідея.
— Давай створимо анотацію @Person, де будемо зберігати: життя, силу, магію, а також параметри атаки та захисту. Ось як би виглядала така анотація:
@interface Person
{
String name() default "";
int live();
int strength();
int magic() default 0;
int attack() default 0;
int defense();
}
А ось такий вигляд мав би опис, наприклад, лісового ельфа-мага:
@Person(live=100, strength=10, magic=5, attack=20, defense=20)
class Elf
{
…
}
А ось такий вигляд мав би опис головного злодія:
@Person(live=1000, strength=150, magic=250, attack=99, defense=99)
class EvilMaster
{
…
}
— Ясно. Чимось нагадує інтерфейси-маркери.
— Так, але, по-перше, нема потреби щось успадковувати, по-друге, в анотаціях можна зберігати додаткову інформацію.
Є ще кілька анотацій, якими позначаються анотації. Ось вони:
Анотація @Retention вказує, де буде видно нашу анотацію: лише в початковому коді, ще й після компіляції, чи буде доступна навіть під час виконання програми.
Анотація @Target вказує, що саме можна позначити цією анотацією: клас, поле, метод, параметр методу тощо.
Якщо ми хочемо, щоб наша анотація діяла не лише на клас, який вона позначає, але й на його нащадків, треба позначити її @Inherited.
Ось як виглядатиме наша анотація @Person.
@Target(value=ElementType.TYPE)
@Retention(value=RetentionPolicy.RUNTIME)
@interface Person
{
String name() default "";
int live();
int strength();
int magic() default 0;
int attack() default 0;
int defense();
}
— Це було дуже цікаво, дякую!
А як працювати з цими анотаціями у програмі? Як їх використати? Як прочитати їх значення?
— Для цього використовують Reflection.
Ось як виглядало б визначення того, який із персонажів сильніший:
public boolean fight(Class first, Class second)
{
if (!first.isAnnotationPresent(Person.class))
throw new RuntimeException("first param is not game person");
if (!second.isAnnotationPresent(Person.class))
throw new RuntimeException("second param is not game person");
Person firstPerson = (Person) first.getAnnotation(Person.class);
Person secondPerson = (Person) second.getAnnotation(Person.class);
int firstAttack = firstPerson.attack() * firstPerson.strength() + firstPerson.magic();
int firstPower = firstPerson.live() * firstPerson.defense() * firstAttack;
int secondAttack = secondPerson.attack() * secondPerson.strength() + secondPerson.magic();
int secondPower = secondPerson.live() * secondPerson.defense() * secondAttack;
return firstPower > secondPower;
}
Ось методи класу, які нам потрібні:
Методи | Опис |
---|---|
|
Перевіряє, чи є в класу необхідна анотація |
|
Повертає об'єкт-анотацію, якщо така є в класу |
|
Повертає масив усіх анотацій класу |
— Чудово. Я й подумати не міг, що отримати анотацію так просто.
— Ага. Просто виклич метод getAnnotation в об'єкта класу, і передай туди потрібний тобі тип анотації.
На цьому все!
— Дякую за дуже цікаву лекціію. Тепер я вже не боюся анотацій, як води.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ