創建註釋是一個相當簡單的過程,儘管它受到某些規則的限制。現在我們需要弄清楚它們的實際用途是什麼。

讓我們回想一下我們是如何創建自己的註解的。

我們將為類和方法編寫一個註釋,並包含有關代碼作者和版本的信息:


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Info {
   String author() default "Author";
   String version() default "0.0";
}

這是我們註釋的類:


@Info
public class MyClass1 {
   @Info
   public void myClassMethod() {}
}
 
@Info(version = "2.0")
public class MyClass2 {
   @Info(author = "Anonymous")
   public void myClassMethod() {}
}
 
@Info(author = "Anonymous", version = "2.0")
public class MyClass3 {
   @Info(author = "Anonymous", version = "4.0")
   public void myClassMethod() {}
}

我們如何在運行時使用這些數據?

通過使用反射從註釋中提取元數據。回想一下反射是什麼。反射是一種在運行時檢查程序數據的機制。反射讓您獲得有關字段、方法、類構造函數和類的信息。

我們將使用反射來讀取類中的註釋並顯示我們想要的信息。

我們將在main方法中從我們的類中讀取數據:


import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
 
public class Main {
   public static void main(String[] args) throws NoSuchMethodException {
       readMyClass(MyClass1.class);
       readMyClass(MyClass2.class);
       readMyClass(MyClass3.class);
   }
 
   static void readMyClass(Class<?> myClassObj) throws NoSuchMethodException {
       System.out.println("\nClass: " + myClassObj.getName());
       readAnnotation(myClassObj);
       Method method = myClassObj.getMethod("myClassMethod");
       readAnnotation(method);
   }
 
   static void readAnnotation(AnnotatedElement element) {
       try {
           System.out.println("Search for annotations in " + element.getClass().getName());
           Annotation[] annotations = element.getAnnotations();
           for (Annotation annotation : annotations) {
               if (annotation instanceof Info) {
                   final Info fileInfo = (Info) annotation;
                   System.out.println("Author: " + fileInfo.author());
                   System.out.println("Version: " + fileInfo.version());
               }
           }
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}

我們將我們類的一個實例傳遞給readMyClass方法。

然後我們可以將一個類和一個方法傳遞給readAnnotation方法。讓我們這樣做——我們將傳遞一個 Class 對象和一個 Method 對象。它需要一個實現AnnotatedElement接口的對象。這使我們可以從對像中獲取註釋列表並獲取有關每個註釋的信息。

請注意,我們只有在檢查註解是否屬於我們的註解類型後才能獲取信息:if (annotation instanceof Info)

程序輸出為我們提供了來自註釋的完整信息:

Class: annotation.MyClass1
在java.lang.Class中搜索註解
作者: Author
Version: 0.0
在java.lang.reflect.Method中搜索註解
作者: Author
Version: 0.0

Class: annotation.MyClass2
在java.lang中搜索註解。類
作者:Author
版本:2.0
java.lang.reflect.Method 中搜索註解
作者:Anonymous
版本:0.0

類:annotation.MyClass3
java.lang.Class 中搜索註解
作者:Anonymous
版本:2.0
java 中搜索註解。 lang.reflect.Method
作者:匿名
版本:4.0

因此,在反射的幫助下,我們能夠提取元數據。

現在讓我們看一個使用註釋來改進代碼的示例,包括總體上提高可讀性、速度和質量。龍目島將幫助我們解決這個問題。

Lombok 是一個編譯器插件,它使用註釋來隱藏大量代碼並擴展語言,從而簡化開發並添加一些功能。

考慮來自 Lombok 的註釋示例:

@ToString 生成toString()方法的實現,該方法由對象的完整表示組成:類名、所有字段及其值。

@ToString
public class Example
@EqualsAndHashCode 生成默認使用非靜態和非靜態字段但可配置的equalshashCode的實現。 可以在該項目的網站上找到更多詳細信息。在那裡您會找到一個使用@EqualsAndHashCode 的示例,並且還顯示了一個沒有註釋的標準實現。
@Getter / @Setter 為私有字段生成 getter 和 setter。

@Getter 
@Setter 
private String name = "name";
@非空 用於在實例化對象時斷言字段不為空。否則,將拋出NullPointerException 。

public Example(@NonNull P p) {
 super("Hello");
 this.name = p.getName();
}

Lombok 有更多有用的註解,但使用頻率較低。我們已經考慮了它最簡單的註解。您可以在官方網站上閱讀有關該項目的更多信息。