Понимание аннотации в Java
Я пытался просмотреть некоторые онлайн-материалы, чтобы узнать аннотацию в java.
В следующем коде, что случилось с моей дорогой "Hello world", которую я передал в этой строке: @Test_Target(doTestTarget="Hello World !")
?
@Target(ElementType.METHOD)
public @interface Test_Target {
public String doTestTarget();
}
выше приведенная аннотация, а ниже - ее использование
public class TestAnnotations {
@Test_Target(doTestTarget="Hello World !")
private String str;
public static void main(String arg[]) {
new TestAnnotations().doTestTarget();
}
public void doTestTarget() {
System.out.printf("Testing Target annotation");
}
}
Когда я запускаю этот код, он печатает только Testing Target annotation
Пожалуйста, помогите мне, я совершенно новичок в аннотации.
Ответы
Ответ 1
Аннотации - это в основном биты данных, которые можно присоединить к полям, методам, классам и т.д.
Синтаксис объявления аннотаций в Java немного неудобен. Они немного похожи на интерфейсы (они, в конце концов, объявлены с помощью @interface
), но они не являются интерфейсами. Я думаю, вы могли бы поместить метод doTestTarget()
в ваш класс TestAnnotations
, потому что вы считали, что ваша аннотация - это интерфейс, и вам нужно его реализовать. Это неверно: вы можете удалить этот метод и вызвать его из своего кода, если хотите, и это не вызовет никаких проблем.
Кроме того, возможно, вы не планировали помещать аннотацию в поле str
. Аннотации применяются только к тому, что сразу следует за ними. В результате ваш код не компилируется, потому что вы применили аннотацию к полю, но объявили, что ваша аннотация может применяться только к методам. Измените @Target(ElementType.METHOD)
на @Target(ElementType.FIELD)
, и тогда ваш код должен скомпилироваться.
Что касается строки Hello World !
, она записывается в файл .class и доступна любому инструменту, который читает в Java-классах. Однако это не обязательно будет доступно в JVM во время выполнения. Это происходит потому, что вы не указали @Retention
для аннотации @Test_Target
. Значение по умолчанию для @Retention
равно RetentionPolicy.CLASS
, что означает, что JVM, возможно, не захочет загрузить их из файла класса. (См. Javadoc для перечисления RetentionPolicy.)
Я предполагаю, что вы хотите увидеть какой-то способ чтения ценности из этой аннотации во время выполнения. Если это так, я бы рекомендовал добавить @Retention(RetentionPolicy.RUNTIME)
к вашей аннотации, чтобы убедиться, что она будет доступна во время выполнения.
Чтобы получить доступ к вашей аннотации и значениям, содержащимся в ней во время выполнения, вам необходимо использовать отражение. Я переписал ваш класс TestAnnotations
следующим образом, чтобы дать быструю демонстрацию:
import java.lang.reflect.Field;
public class TestAnnotations {
@Test_Target(doTestTarget="Hello World !")
private String str;
public static void main(String[] args) throws Exception {
// We need to use getDeclaredField here since the field is private.
Field field = TestAnnotations.class.getDeclaredField("str");
Test_Target ann = field.getAnnotation(Test_Target.class);
if (ann != null) {
System.out.println(ann.doTestTarget());
}
}
}
Когда я запускаю этот код, он дает мне следующий вывод:
Hello World !
Ответ 2
В принципе, добавление аннотации само по себе не в корне меняет поведение программ.
В вашем случае вы создали новый тип аннотации @Test_Target
, который может использоваться любым способом (как указано в его аннотации @Target
).
Затем вы применили это не к методу, а к полю str
(что должно дать ошибку компилятора, я думаю).
Независимо от этого вы создаете объект с помощью метода doTestTarget
и вызываете его и получаете ожидаемый результат (т.е. метод выполняется).
Если вы хотите, чтобы ваша аннотация делала что-то большее, чем просто быть там, и предоставляла некоторую информацию для читателя источника, вы должны использовать ее - либо с обработчиком аннотации во время компиляции, либо с использованием отражения во время выполнения (тогда вам понадобится @Retention(RUNTIME)
в качестве аннотации на Test_Target
.)
Ответ 3
В духе обучения другим способом является использование аннотированного класса без таргетинга на метод или поле.
Сначала объявите свой интерфейс с помощью метода, который вам нужен, и политики хранения в Runtime
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
public @interface Test_Target {
public String doTestTarget() default "default string";
}
затем аннотируйте интерфейс, созданный для вашего класса. Из вашего класса найдите аннотированный класс, а затем вызовите метод с ним.
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
@Test_Target(doTestTarget="Hello World !")
public class TestAnnotations {
public static void main(String[] args) throws Exception
{
AnnotatedElement c = TestAnnotations.class;
if(c.isAnnotationPresent(Test_Target.class))
{
Annotation singleAnnotation = c.getAnnotation(Test_Target.class);
Test_Target tt = (Test_Target) singleAnnotation;
System.out.println(tt.doTestTarget());
}
}
}
результат:
Привет, мир!