Java 8 註解探秘
Java SE 1.5引入了註解,程式設計師透過註解可以為程式編寫後設資料(metadata)。根據 Oracle 官方文件,註解的定義如下:“ 註解是後設資料的一種形式,提供與程式相關的資料,該資料不是程式本身的一部分”。
可以在程式碼中的任何位置使用註解,比如類、方法和變數上使用。從 Java 8開始,註解也可以用於型別宣告。
註解程式碼與程式本身沒有任何直接關係,只有其他程式或 JVM 利用註解資訊實現特定功能。
註解語法
註解由字元 @ 和註解名組成,即 @AnnotationName。當編譯器發現這個語法該元素時,會把它解析為註解。例如:
@ExampleAnnotation
public
class SampleClass {
}
上面的註解稱為 ExampleAnnotation,標記在 SampleClass 上。
註解可以包含屬性,在宣告註解時以鍵值對的形式給出。例如:
@ExampleAnnotation(name = ”first name”, age =
35)
public
void
simpleMethod
() {
}
請注意,這裡 ExampleAnnotation 是一個方法註解。如果註解只包含一個屬性,在宣告註解時可以忽略屬性名。示例如下:
@ExampleAnnotation(“I am the only property”)
public
void
simpleMethod
() {
}
一個元素可以使用多個註解。比如下面這個示例:
@Annotation1
@Annotation2(“Another Annotation”)
public
class SimpleClass {
}
從 J2SE 8 開始,可以為同一個元素多次使用相同的註解,例如:
@ExampleAnnotation(“Annotation used”)
@ExampleAnnotation(“Annotation repeated”)
public
class SimpleClass {
}
在 @Repeatable 部分會對此進行詳細地討論。
Java 預定義註解
Java 支援一組預先定義好的註解。下面介紹了Java Core 中提供的註解:
@Retention: 該註解用來修飾其他註解,並標明被修飾註解的作用域。其 value 的屬性值包含3種:
-
SOURCE:註解僅在原始碼中可用。編譯器和 JVM 會忽略此註解,因此在執行時不可用;
-
CLASS:編譯器會處理該註解,但 JVM 不會處理,因此在執行時不可用;
-
RUNTIME:JVM 會處理該註解,可以在執行時使用。
@Targe t: 該註解標記可以應用的目標元素:
-
ANNOTATION_TYPE:可修飾其他註解;
-
CONSTRUCTOR:可以修飾建構函式;
-
FIELD:可以修飾欄位或屬性;
-
LOCAL_VARIABLE:可以修飾區域性變數;
-
METHOD:可以修飾 method;
-
PACKAGE:可以修飾 package 宣告;
-
PARAMETER:可以修飾方法引數;
-
TYPE:可以修飾 Class、Interface、Annotation 或 enum 宣告;
-
PACKAGE:可以修飾 package 宣告;
-
TYPE_PARAMETER:可以修飾引數宣告;
-
TYPE_USE:可以修飾任何型別。
@Documented: 該註解可以修飾其他註解,表示將使用 Javadoc 記錄被註解的元素。
@Inherited: 預設情況下,註解不會被子類繼承。但是,如果把註解標記為 @Inherited,那麼使用註解修飾 class 時,子類也會繼承該註解。該註解僅適用於 class。注意:使用該註解修飾介面時,實現類不會繼承該註解。
@Deprecated: 標明不應該使用帶此註解的元素。使用這個註解,編譯器會對應生成告警。該註解可以應用於 method、class 和欄位。
@SuppressWarnings: 告訴編譯器由於特定原因不產生告警。
@Override: 該註解通知編譯器,該元素正在覆蓋(Override)父類中的元素。覆蓋元素時,不強制要求加上該註解。但是當覆蓋沒有正確完成時,例如子類方法的引數與父類引數不同或者返回型別不匹配時,可以幫助編譯器生成錯誤。
@SafeVarargs: 該註解斷言(Assert)方法或建構函式程式碼不會對其引數執行不安全(Unsafe)操作。
@Repeatable 註解
該註解表示可以對同一個元素多次使用相同的註解。
下面這個例子有助於更清楚地理解。
首先,需要定義一個可重複修飾 class 的註解。
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.TYPE_USE)
@Repeatable (RepeatableAnnotationContainer.
class)
public @
interface
RepeatableAnnotation
() {
String
values
();
}
RepeatableAnnotation可以重複修飾元素。
接下來,定義 RepeatableAnnotationContainer註解型別。這是一個註解型別容器,包含一個 RepeatableAnnotation 型別的陣列。
public @interface RepeatableAnnotationContainer {
RepeatableAnnotation [] value();
}
現在,Repeatable 可以元素進行多次註釋。
@RepeatableAnnotation (“I am annotating the
class
”)
@RepeatableAnnotation (“I am annotating the
class
again”)
@RepeatableAnnotation (“I am annotating the
class
for
the third time”)
public
class
RepeatedAnnotationExample {
function(){ //外匯跟單
}
在程式中要獲取註解中的值,先要獲取容器中的陣列,陣列的每個元素將包含一個值。例如:
@RepeatableAnnotation (“I am annotating the
class”)
@RepeatableAnnotation (“I am annotating the
class again”)
@RepeatableAnnotation(“I am annotating the
class
for the third time”)
public
class RepeatableAnnotationExample {
public
static
void
main
(String [] args) {
Class object = RepeatableAnnotationExample.
class
Annotation[] annotations = object.getAnnotations();
for (Annotation annotation : annotations) {
RepeatableAnnotationContainer rac = (RepeatableAnnotationContainer) annotation;
RepeatableAnnotation [] raArray = rac.value();
for (RepeatableAnnotation ra : raArray) {
System.out.println(ra.value);
}
}
}
}
執行結果:
I am annotating the
class
I am annotating the
class again
I am annotating the
class
for the third time.
型別註解
Java 8釋出後,註解可以用於任何型別(Type),這意味著只要可以使用型別的地方就能使用註解。例如,使用新運算子建立類例項、型別轉換、用 implements 實現介面、丟擲異常等,這種註解稱為型別註解。
這種註解能夠幫助分析與改進 Java 程式,提供更強大的型別檢查。Java 8釋出前,Java 沒有提供型別檢查框架。但是透過型別註解可以開發型別檢查框架,對 Java 程式進行檢查。
舉例來說,假設我們希望特定變數在程式執行過程中始終不為 null。可以編寫一個自定義外掛 NonNull,併為特定變數加上該註解進行檢查。變數宣告如下:
@NonNull String notNullString;
編譯程式碼時,如果發現任何可能將變數賦值為 null 的程式碼,編譯器會檢查潛在問題並給出告警。
自定義註解
Java 允許程式設計師自定義註解。自行定義註解的語法:
public @interface CustomAnnotation { }
上面的程式碼會建立一個 CustomAnnotation新註解。@Interface 關鍵字可用於自定義註解。
自定義註解時,必須設定兩個必填屬性。可以在定義中增加其他屬性,但這兩個重要屬性是必需的,即 Retention Policy 和 Target 。
這兩個屬性(註解)被用來修飾自定義註解。此外,在自定義註解時可以定義屬性。例如:
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.ELEMENT)
public @interface CustomAnnotation {
public String
name
()
default “Mr Bean”;
public String
dateOfBirth
();
}
上面的自定義註解中,Retention Policy 為 RUNTIME,這表明該註解可以在 JVM 執行時使用;Target 設為 ELEMENT,表示該註解可以修飾任何元素與型別。
此外,它還具有兩個屬性:name 與 dateOfBirth。其中,name 屬性預設值為 Mr Bean, dateOfBirth 沒有預設值。
注意,宣告的 Method 沒有帶任何引數以及 throws 語句。此外,返回型別僅限於 String、class、enum、註解以及上述型別的陣列。
現在,可以像下面這樣使用自定義註解:
@CustomAnnotation (dateOfBirth = “
1980-06-25”)
public
class CustomAnnotatedClass {
}
同樣,可以使用 @Target(ElementType.METHOD) 建立自定義註解修飾 method。
獲取註解及屬性
Java Reflection API 提供了幾種方法,可以在執行時中從 class、method 和其他元素中獲取註解。
AnnotatedElement介面定義了所有的方法,其中最重要的一個是:
-
getAnnotations(): 返回指定元素的所有註解,包括定義元素時未明確寫出的註解。
-
isAnnotationPresent(annotation): 檢查註解在當前元素上是否可用。
-
getAnnotation(class): 獲取 class 引數使用的註解,如果引數不存在註解返回 null。
這個 class 支援 java.lang.Class、java.lang.reflect.Method 和 java.lang.reflect.Field,基本上可以適用任何的 Java 元素。
下面的示例程式展示瞭如何獲取自定義註解的相關資訊:
public
static
void
main
(String [] args) {
Class object = CustomAnnotatedClass.
class;
// 從類中獲取所有註解
Annotation[] annotations = object.getAnnotations();
for( Annotation annotation : annotations ) {
System.out.println(annotation);
}
// 檢查是否存在註解
if( object.isAnnotationPresent( CustomAnnotationClass.
class ) ) {
// 獲取需要的註解
Annotation annotation = object.getAnnotation(CustomAnnotationClass.
class) ;
System.out.println(annotation);
}
// 獲取註解屬性
for(Annotation annotation : annotations) {
System.out.println(“name: “ + annotation.name());
System.out.println(“Date of Birth: “+ annotation.dateOfBirth());
}
// 對所有方法執行相同的操作
for( Method method : object.getDeclaredMethods() ) {
if( method.isAnnotationPresent( CustomAnnotationMethod.
class ) ) {
Annotation annotation = method.getAnnotation(CustomAnnotationMethod.
class );
System.out.println( annotation );
}
}
}
總結
註解逐漸成為 J2EE 開發棧的重要組成部分,在開發任何企業級應用都需要用到。 現如今,幾乎所有流行的開發庫出於不同目的都開始使用註解,比如程式碼質量分析、單元測試、XML 解析、依賴項注入等。 大量使用了註解的開發庫有 Hibernate、Spring MVC、Findbugs、JAXB 和 JUnit。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946337/viewspace-2662221/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【譯】8. Java反射——註解Java反射
- java註解Java
- 註解 javaJava
- Java註解詳解Java
- Java 註解詳解Java
- 【Java8新特性】重複註解與型別註解,你真的學會了嗎?Java型別
- JAVA-註解(2)-自定義註解及反射註解Java反射
- 註解專題(一)Java元註解,內建註解Java
- Java中的註解-自定義註解Java
- JAVA 註解 AnnontationJava
- Java註解AnnotatonJava
- Java反射-註解Java反射
- Java™ 教程(註解)Java
- Java —— 註解(Annotation)Java
- Java(5)註解Java
- java註解,反射Java反射
- Java Annotation 註解Java
- Java--註解Java
- Java 註解(Annotation)Java
- Java註解詳解「註解專案實戰」Java
- Java註解(Annotation)詳解Java
- 深入理解 Java 註解 [元註解(一)]Java
- Java 註解完全解析Java
- 自定義JAVA註解Java
- Java 註解全面解析Java
- Java反射與註解Java反射
- java-Annotation註解Java
- 初識 Java 註解Java
- Java之註解(Annotation)Java
- Java學習_註解Java
- Java註解的使用Java
- Java 註解和反射Java反射
- Java基礎——註解Java
- Java註解全面解析Java
- java 自定義註解Java
- Java 自定義註解Java
- Java 註解介紹Java
- Java 註解Annotation研究Java