- Stwórzmy teraz kilka adnotacji i użyjmy ich.

Na przykład piszemy silnik do gry. Jednocześnie w grze mamy do czynienia z wieloma postaciami, które podzielone są na trzy kategorie: elfy, pałacowi strażnicy oraz złoczyńca.

Podczas rozwoju gry mogą zostać dodane nowe postacie, a balans gry ulegnie zmianie. Dlatego bardzo wygodnie byłoby przypisać każdej „klasie postaci” własną adnotację opisującą jej cechy fizyczne.

Wtedy bardzo łatwo byłoby symulować walki między różnymi postaciami i/lub szybko obliczyć balans gry.

Zgadzam się - to dobry pomysł.

- Stwórzmy adnotację  @Person , w której będziemy przechowywać: życie, siłę, magię, a także parametry ataku i obrony. Oto jak wyglądałaby adnotacja:

Przykład
@interface Person
{
 String name() default "";
 int live();
 int strength();
 int magic() default 0;
 int attack() default 0;
 int defense();
}

A tak wyglądałby np. opis maga leśnych elfów:

Przykład
@Person(live=100, strength=10, magic=5, attack=20, defense=20)
class Elf
{}

Oto jak wyglądałby opis głównego złoczyńcy:

Przykład
@Person(live=1000, strength=150, magic=250, attack=99, defense=99)
class EvilMaster
{}

- Jasne. Coś w rodzaju znaczników interfejsu.

- Tak, ale po pierwsze nie trzeba niczego dziedziczyć, a po drugie dodatkowe informacje można przechowywać w adnotacjach.

Jest jeszcze kilka  adnotacji, które oznaczają adnotacje. Tutaj są:

Adnotacja @Retention wskazuje, gdzie nasza adnotacja będzie widoczna: tylko w kodzie źródłowym, nawet po kompilacji, będzie dostępna nawet podczas wykonywania programu.

Adnotacja @Target określa, co dokładnie można oznaczyć tą adnotacją: klasę, pole, metodę, parametr metody i tak dalej.

Jeśli chcemy, aby nasza adnotacja działała nie tylko na oznaczoną nią klasę, ale również na jej potomków, to musimy ją oznaczyć @Inherited.

Tak  będzie wyglądać nasza adnotacja @Person.

Przykład
@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();
}

— To było bardzo interesujące, dziękuję Risza.

A jak pracować z tymi adnotacjami w programie? Jak z nich korzystać? Jak odczytywać ich wartości?

- Zwyczajowo używa się do tego  Odbicia .

Oto jak wyglądałoby ustalenie, która z postaci jest silniejsza:

Przykład
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;
}

Oto metody klas, których potrzebujemy:

Metody Opis
isAnnotationPresent(Annotation.class)
Sprawdza, czy klasa ma żądaną adnotację
getAnnotation(Annotation.class)
Zwraca obiekt adnotacji, jeśli klasa go posiada.
Annotation[] getAnnotations()
Zwraca tablicę wszystkich adnotacji klas

- Świetnie. I nie sądziłem, że zdobycie adnotacji jest takie łatwe.

- Tak. Właśnie wywołałem metodę getAnnotation na obiekcie klasy i przekazałem tam typ adnotacji, którego potrzebujesz.

To wszystko na dzisiaj.

— Dziękuję, Risza, to był bardzo ciekawy wykład. A teraz nie boję się już adnotacji jak woda.