Понимание аннотации в 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());
    }       
}

}

результат: Привет, мир!