創建註釋是一個相當簡單的過程,儘管它受到某些規則的限制。現在我們需要弄清楚它們的實際用途是什麼。
讓我們回想一下我們是如何創建自己的註解的。
我們將為類和方法編寫一個註釋,並包含有關代碼作者和版本的信息:
@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
在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()方法的實現,該方法由對象的完整表示組成:類名、所有字段及其值。 |
|
@EqualsAndHashCode | 生成默認使用非靜態和非靜態字段但可配置的equals和hashCode的實現。 | 可以在該項目的網站上找到更多詳細信息。在那裡您會找到一個使用@EqualsAndHashCode 的示例,並且還顯示了一個沒有註釋的標準實現。 |
@Getter / @Setter | 為私有字段生成 getter 和 setter。 |
|
@非空 | 用於在實例化對象時斷言字段不為空。否則,將拋出NullPointerException 。 |
|
Lombok 有更多有用的註解,但使用頻率較低。我們已經考慮了它最簡單的註解。您可以在官方網站上閱讀有關該項目的更多信息。
GO TO FULL VERSION