"Agora vamos criar e usar algumas anotações."

"Por exemplo, digamos que estamos escrevendo um mecanismo de jogo. Nosso jogo tem muitos personagens que se enquadram em três categorias: elfos, guardas do palácio e vilões."

"Com o desenvolvimento do jogo, novos personagens podem ser adicionados, e isso vai alterar o equilíbrio do jogo. Assim, seria muito conveniente atribuir a cada 'classe de personagem' uma anotação própria que descreva suas características físicas."

"Fazer isso tornaria muito fácil simular batalhas entre diferentes personagens e/ou calcular rapidamente o equilíbrio do jogo."

"Eu concordo. É uma boa ideia."

"Vamos criar uma anotação @Person que armazenará vida, força e magia, bem como parâmetros de ataque e defesa. Veja como fica a anotação:"

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

"E, como exemplo, aqui está a descrição de um mago elfo da floresta:"

Exemplo
@Person(live = 100, strength = 10, magic = 5, attack = 20, defense = 20)
class Elf
{
 …
}

"E aqui está como ficaria a descrição do vilão principal:"

Exemplo
@Person(live = 1000, strength = 150, magic = 250, attack = 99, defense = 99)
class EvilMaster
{
 …
}

"Entendo. Isso me lembra um pouco as interfaces de marcadores."

"Sim. Exceto, primeiro, você não precisa herdar nada. E segundo, você pode armazenar informações adicionais em anotações."

"Existem mais algumas anotações usadas para marcar anotações. Aqui estão elas: "

"A anotação @Retention indica onde nossa anotação ficará visível: somente no código-fonte, mesmo após a compilação, ou mesmo em tempo de execução."

"A anotação @Target indica o que especificamente pode ser marcado usando a anotação: classes, campos, métodos, parâmetros de método, etc."

"Se quisermos que nossa anotação seja aplicada a classes que herdam uma classe anotada e não apenas à própria classe anotada, precisamos anotá-la com @Inherited."

"É assim que nossa anotação @Person. ficaria."

Exemplo
@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 defence();
}

"Isso foi muito interessante, obrigado, Rishi."

Mas como você trabalha com essas anotações no programa? Como você os usa? Como você lê seus valores?"

"Isso geralmente é feito usando o Reflection ."

"Aqui está como determinaríamos qual personagem é mais forte:"

Exemplo
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.defence() * firstAttack;

 int secondAttack = secondPerson.attack() * secondPerson.strength() + secondPerson.magic();
 int secondPower = secondPerson.live() * secondPerson.defence() * secondAttack;

 return firstPower > secondPower;
}

"Aqui estão os métodos que precisamos:"

Métodos Descrição
isAnnotationPresent(Annotation.class)
Verifica se a classe tem a anotação especificada
getAnnotation(Annotation.class)
Retorna um objeto de anotação se a classe tiver a anotação especificada.
Annotation[] getAnnotations()
Retorna um array de todas as anotações da classe

"Ótimo. Eu não esperava que obter uma anotação fosse tão simples."

"Uh-huh." Basta chamar o método getAnnotation do objeto, passando o tipo de anotação desejado."

"Por hoje é isso."

"Obrigado, Rishi. Esta foi uma lição muito interessante. Agora não tenho medo de anotações como tenho medo de água."