Perguntas da entrevista sobre anotações em Java (+ respostas)
1. Introdução
As anotações existem desde o Java 5 e atualmente são construções onipresentes de programação que permitem enriquecer o código.
Neste artigo, revisaremos algumas das perguntas relacionadas às anotações; que são frequentemente questionados em entrevistas técnicas e, quando apropriado; vamos implementar exemplos para entender melhor suas respostas.
2. Questões
Q1. O que são anotações? Quais são seus casos de uso típicos?
As anotações são metadados vinculados a elementos do código fonte de um programa e não têm efeito na operação do código em que operam.
Seus casos de uso típicos são:
-
Information for the compiler - com anotações, o compilador pode detectar erros ou suprimir avisos
-
Compile-time and deployment-time processing - ferramentas de software podem processar anotações e gerar código, arquivos de configuração, etc.
-
Runtime processing - as anotações podem ser examinadas em tempo de execução para personalizar o comportamento de um programa
Q2. Descreva algumas anotações úteis da biblioteca padrão.
Existem várias anotações nos pacotesjava.langejava.lang.annotation, as mais comuns incluem, mas não se limitam a:
-
@Override – marca que um método deve substituir um elemento declarado em uma superclasse. Se ele não substituir o método corretamente, o compilador emitirá um erro
-
@Deprecated - indica que o elemento está obsoleto e não deve ser usado. O compilador emitirá um aviso se o programa usar um método, classe ou campo marcado com esta anotação
-
@SuppressWarnings - diz ao compilador para suprimir avisos específicos. Mais comumente usado ao fazer interface com o código herdado escrito antes da exibição dos genéricos
-
@FunctionalInterface - introduzido no Java 8, indica que a declaração de tipo é uma interface funcional e cuja implementação pode ser fornecida usando uma expressão Lambda
Q3. Como você pode criar uma anotação?
As anotações são uma forma de interface onde a palavra-chaveinterface é precedida por@, e cujo corpo contém declaraçõesannotation type element que se parecem muito com métodos:
public @interface SimpleAnnotation {
String value();
int[] types();
}
Depois que a anotação é definida, você pode começar a usá-la através do seu código:
@SimpleAnnotation(value = "an element", types = 1)
public class Element {
@SimpleAnnotation(value = "an attribute", types = { 1, 2 })
public Element nextElement;
}
Observe que, ao fornecer vários valores para elementos da matriz, você deve colocá-los entre colchetes.
Opcionalmente, os valores padrão podem ser fornecidos desde que sejam expressões constantes para o compilador:
public @interface SimpleAnnotation {
String value() default "This is an element";
int[] types() default { 1, 2, 3 };
}
Agora, você pode usar a anotação sem esses elementos:
@SimpleAnnotation
public class Element {
// ...
}
Ou apenas alguns deles:
@SimpleAnnotation(value = "an attribute")
public Element nextElement;
Q4. Quais tipos de objeto podem ser retornados de uma declaração de método de anotação?
O tipo de retorno deve ser uma primitiva,String,Class,Enum ou uma matriz de um dos tipos anteriores. Caso contrário, o compilador lançará um erro.
Aqui está um exemplo de código que segue este princípio com sucesso:
enum Complexity {
LOW, HIGH
}
public @interface ComplexAnnotation {
Class extends Object> value();
int[] types();
Complexity complexity();
}
O próximo exemplo falhará ao compilar, poisObject não é um tipo de retorno válido:
public @interface FailingAnnotation {
Object complexity();
}
Q5. Quais elementos do programa podem ser anotados?
As anotações podem ser aplicadas em vários locais em todo o código-fonte. Eles podem ser aplicados a declarações de classes, construtores e campos:
@SimpleAnnotation
public class Apply {
@SimpleAnnotation
private String aField;
@SimpleAnnotation
public Apply() {
// ...
}
}
Métodos e seus parâmetros:
@SimpleAnnotation
public void aMethod(@SimpleAnnotation String param) {
// ...
}
Variáveis locais, incluindo um loop e variáveis de recurso:
@SimpleAnnotation
int i = 10;
for (@SimpleAnnotation int j = 0; j < i; j++) {
// ...
}
try (@SimpleAnnotation FileWriter writer = getWriter()) {
// ...
} catch (Exception ex) {
// ...
}
Outros tipos de anotação:
@SimpleAnnotation
public @interface ComplexAnnotation {
// ...
}
E até pacotes, por meio do arquivopackage-info.java:
@PackageAnnotation
package com.example.interview.annotations;
A partir do Java 8, eles também podem ser aplicados aosuse dos tipos. Para que isso funcione, a anotação deve especificar uma anotação@Target com um valor deElementType.USE:
@Target(ElementType.TYPE_USE)
public @interface SimpleAnnotation {
// ...
}
Agora, a anotação pode ser aplicada à criação da instância de classe:
new @SimpleAnnotation Apply();
Tipo molda:
aString = (@SimpleAnnotation String) something;
Cláusula de implementação:
public class SimpleList
implements @SimpleAnnotation List<@SimpleAnnotation T> {
// ...
}
E a cláusulathrows:
void aMethod() throws @SimpleAnnotation Exception {
// ...
}
Q6. Existe uma maneira de limitar os elementos nos quais uma anotação pode ser aplicada?
Sim, a anotação@Target pode ser usada para esse propósito. Se tentarmos usar uma anotação em um contexto em que não é aplicável, o compilador emitirá um erro.
Aqui está um exemplo para limitar o uso da anotação@SimpleAnnotation apenas para declarações de campo:
@Target(ElementType.FIELD)
public @interface SimpleAnnotation {
// ...
}
Podemos passar várias constantes se queremos torná-lo aplicável em mais contextos:
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PACKAGE })
Podemos até fazer uma anotação para que ela não possa ser usada para anotar nada. Isso pode ser útil quando os tipos declarados se destinam apenas ao uso como um tipo de membro em anotações complexas:
@Target({})
public @interface NoTargetAnnotation {
// ...
}
Q7. O que são metanotações?
São anotações que se aplicam a outras anotações.
Todas as anotações que não estão marcadas com@Target, ou estão marcadas com ele, mas incluem a constanteANNOTATION_TYPE também são meta-anotações:
@Target(ElementType.ANNOTATION_TYPE)
public @interface SimpleAnnotation {
// ...
}
Q8. O que são anotações repetidas?
Essas são anotações que podem ser aplicadas mais de uma vez na mesma declaração de elemento.
Por motivos de compatibilidade, como esse recurso foi introduzido no Java 8, as anotações repetidas são armazenadas em umcontainer annotation que é gerado automaticamente pelo compilador Java. Para o compilador fazer isso, há duas etapas para declará-los.
Primeiro, precisamos declarar uma anotação repetível:
@Repeatable(Schedules.class)
public @interface Schedule {
String time() default "morning";
}
Em seguida, definimos a anotação de conteúdo com um elementovalue obrigatório, e cujo tipo deve ser uma matriz do tipo de anotação repetível:
public @interface Schedules {
Schedule[] value();
}
Agora, podemos usar o @Schedule várias vezes:
@Schedule
@Schedule(time = "afternoon")
@Schedule(time = "night")
void scheduledMethod() {
// ...
}
Q9. Como você pode recuperar anotações? Como isso se relaciona com sua política de retenção?
Você pode usar a API do Reflection ou um processador de anotações para recuperar anotações.
A anotação@Retention e seu parâmetroRetentionPolicy afetam como você pode recuperá-los. Existem três constantes na enumRetentionPolicy:
-
RetentionPolicy.SOURCE - faz com que a anotação seja descartada pelo compilador, mas os processadores de anotação podem lê-la
-
RetentionPolicy.CLASS - indica que a anotação é adicionada ao arquivo de classe, mas não acessível por meio de reflexão
-
RetentionPolicy.RUNTIME –As anotações são gravadas no arquivo de classe pelo compilador e retidas pela JVM no tempo de execução para que possam ser lidas reflexivamente
Aqui está um exemplo de código para criar uma anotação que pode ser lida no tempo de execução:
@Retention(RetentionPolicy.RUNTIME)
public @interface Description {
String value();
}
Agora, as anotações podem ser recuperadas através da reflexão:
Description description
= AnnotatedClass.class.getAnnotation(Description.class);
System.out.println(description.value());
Um processador de anotações pode trabalhar comRetentionPolicy.SOURCE, isso é descrito no artigoJava Annotation Processing and Creating a Builder.
RetentionPolicy.CLASS pode ser usado quando você está escrevendo um analisador de bytecode Java.
Q10. O código a seguir será compilado?
@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.FIELD })
public @interface TestAnnotation {
int[] value() default {};
}
No. É um erro em tempo de compilação se a mesma constante de enum aparecer mais de uma vez em uma anotação@Target.
A remoção da constante duplicada fará com que o código seja compilado com êxito:
@Target({ ElementType.FIELD, ElementType.TYPE})
Q11. É possível estender anotações?
No. As anotações sempre estendemjava.lang.annotation.Annotation, conforme declarado emJava Language Specification.
Se tentarmos usar a cláusulaextends em uma declaração de anotação, obteremos um erro de compilação:
public @interface AnAnnotation extends OtherAnnotation {
// Compilation error
}
Conclusão
Neste artigo, abordamos algumas das perguntas mais frequentes que aparecem em entrevistas técnicas para desenvolvedores Java, sobre anotações. Esta não é de forma alguma uma lista exaustiva, e deve ser considerada apenas como o início de mais pesquisas.
Nós, por exemplo, desejamos sucesso em todas as próximas entrevistas.