JavaRush /Курсы /Модуль 2. Java Core /Создание своих аннотации

Создание своих аннотации

Модуль 2. Java Core
18 уровень , 3 лекция
Открыта

— Так вот, давай-ка сейчас создадим парочку аннотаций и используем их.

Например, мы пишем движок для игры. При этом у нас в игре очень много персонажей, которые делятся на три категории: эльфы, охрана дворца и злодей.

В процессе разработки игры, могут добавляться новые персонажи, и при этом будет меняться баланс игры. Поэтому было бы очень удобно приписать каждому «классу персонажа» свою аннотацию с описанием его физических характеристик.

Тогда можно было бы очень просто симулировать бои между различными персонажами и/или быстро просчитать баланс игры.

— Согласен – это хорошая идея.

— Давай создадим аннотацию @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;
}

Вот методы класса, которые нам нужны:

Методы Описание
isAnnotationPresent(Annotation.class)
Проверяет, если ли у класса нужная аннотация
getAnnotation(Annotation.class)
Возвращает объект-аннотацию, если такая у класса есть.
Annotation[] getAnnotations()
Возвращает массив всех аннотаций класса

— Отлично. А я и не думал, что получить аннотацию так просто.

— Ага. Просто вызвал метод getAnnotation у объекта класса, и передал туда нужный тебе тип аннотации.

На этом на сегодня все.

— Спасибо, Риша, это была очень интересная лекция. И теперь я уже не боюсь аннотаций как воды.

Комментарии (4)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Ardan Уровень 57
4 июля 2025
Я слишком тупой сначала пытался сделать енам через Enum потом подумал что так не работает решил сделать егов отдельном файле но так тоже не работало в тоге покопался в интернете и вспомнил что делаеться то он

 enum Priority {
        LOW, MEDIUM, HIGH
    }
вот так после чего все заработало кстати еще хотел бы рассказать про RententionPolicy RententionPolicy.SOURCE это когда аннотация нужна только в исходнике , что бы компилятор или человек , при чтении кода посмотрел ( понял некоторые вещи , например: есть по моему аннотация которая указывает на устаревшие методы и тд ) или компплятор прочитал мета информацию и добавил инфы уже в сам class RententionPolicy.CLASS это когда аннотации нужны уже после компиляции , то есть в байт коде , что бы в дальнейшем работать с ними , например: у тебя есть специальный инструмент который проверяет каким классам сделать отчет , исходя из аннотации. Если ты в этой аннотации укажешь RententionPolicy.SOURCE JVM не увидит ее и не сделает никаких отчетов , потому что твоя аннотация умерла еще до того как стала байт кодом RententionPolicy.RUNTIME это когда аннотация меняет ход программы. Например у тебя есть штат сотрудников и у каждого своя должность , каждую должность ты помечаешь своей аннотацией , эти аннотации будут давать конкретные материалы сотруднику в зависимости от должности сотрудника , эту аннотацию нельзя оставить в SOURCE иначе программа просто не увидит ее при запуске и просто ничего не даст твоим сотрудникам и в CLASS то же нельзя оставить по той же причине ну надеюсь понятно хз может я не прав но я так это понял
25 октября 2025
Насчёт тупости ты это зря, я победю😁. А если серьёзно, твой коммент мне оказался полезен. Молодец!
Олег Уровень 106 Expert
28 июля 2024
Вот тут всё понятно, ура!
jvatechs Уровень 111 Expert
8 апреля 2023
Хорошие задачки