2.5 注解
2.5.1 注解簡(jiǎn)介
Annotation是Java提供的一種元程序中的元素關(guān)聯(lián)任何信息和元數(shù)據(jù)(metadata)的途徑和方法。Annotation(注解)是一個(gè)接口,程序可以在編譯期通過(guò)AbstractProcessor處理注解元素,或者運(yùn)行期通過(guò)反射來(lái)獲取指定程序元素的Annotation對(duì)象,然后通過(guò)Annotation對(duì)象來(lái)獲取其中的元數(shù)據(jù)。
在Annotation中,成員以無(wú)參數(shù)的方法的形式被聲明,其方法名和返回值定義了該成員的名字和類型。
2.5.2 元注解
在定義自己的注解之前,我們就必須要了解Java為我們提供的元注解和相關(guān)定義注解的語(yǔ)法。元注解的作用就是負(fù)責(zé)注解其他注解,Java定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類型,它們被用來(lái)提供對(duì)其它annotation類型作說(shuō)明:@Target,@Retention,@Documented,@Inherited,這里我們看一下Target和Retention:
Target
Target說(shuō)明了Annotation所修飾的對(duì)象范圍:Annotation可被用于packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構(gòu)造方法、成員變量、枚舉值)、方法參數(shù)和本地變量(如循環(huán)變量、catch參數(shù))。其取值(ElementType)有:
- CONSTRUCTOR:用于描述構(gòu)造器
- FIELD:用于描述域
- LOCAL_VARIABLE:用于描述局部變量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述參數(shù)
- TYPE:用于描述類、接口(包括注解類型)或enum聲明
Retention
Retention定義了該Annotation被保留的時(shí)間長(zhǎng)短:其取值(RetentionPolicy)有:
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在class文件中有效(即class保留)
- RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)
2.5.3 自定義注解
使用@interface自定義注解時(shí),自動(dòng)繼承了Annotation接口,由編譯程序自動(dòng)完成其他細(xì)節(jié)。@interface用來(lái)聲明一個(gè)注解,其中的每一個(gè)方法實(shí)際上是聲明了一個(gè)配置參數(shù),方法的名稱就是參數(shù)的名稱,返回值類型就是參數(shù)的類型,返回值類型只能是基本類型、Class、String、enum,Annotation以及以上類型的數(shù)組,可以通過(guò)default來(lái)聲明參數(shù)的默認(rèn)值。簡(jiǎn)單的自定義注解和使用注解實(shí)例:
//定義注解FruitName
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
String value() default "";
}
//定義注解FruitColor
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
public enum Color {BLUE, RED, GREEN};
Color fruitColor() default Color.GREEN;
}
//使用注解FruitName,F(xiàn)ruitColor
public class Apple {
@FruitName("Apple")
private String appleName;
@FruitColor(fruitColor=Color.RED)
private String appleColor;
public void setAppleColor(String appleColor) {
this.appleColor = appleColor;
}
public String getAppleColor() {
return appleColor;
}
public void setAppleName(String appleName) {
this.appleName = appleName;
}
public String getAppleName() {
return appleName;
}
public void displayName(){
System.out.println("水果的名字是:蘋果");
}
}
注解元素的默認(rèn)值
注解元素必須有確定的值,要么在定義注解的默認(rèn)值中指定,要么在使用注解時(shí)指定,非基本類型的注解元素的值不可為null。因此使用空字符串或0作為默認(rèn)值是一種常用的做法。一般會(huì)定義一些特殊的值,例如空字符串或者負(fù)數(shù),以此表示某個(gè)元素不存在。
2.5.4 注解處理器
使用注解的過(guò)程中,很重要的一部分就是創(chuàng)建注解處理器。根據(jù)Retention的取值,注解處理器可以分為編譯期處理,運(yùn)行期處理。
運(yùn)行期處理
Java擴(kuò)展了反射API,新增了AnnotatedElement接口,該接口代表程序中可以接受注解的程序元素,該接口主要有如下幾個(gè)實(shí)現(xiàn)類:Class、Constructor、Field、Method和Package。AnnotatedElement聲明了以下四個(gè)方法:
- <T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回該程序元素上存在的、指定類型的注解。
- Annotation[] getAnnotations():返回該程序元素上存在的所有注解。
- boolean isAnnotationPresent(Class<?extends Annotation> annotationClass):判斷該程序元素上是否包含指定類型的注解,存在則返回true,否則返回false.
- Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注,該方法將忽略繼承的注釋。
下面看一個(gè)簡(jiǎn)單的注解處理器:
//該例使用上面定義的注解,定義注解處理器
public class FruitInfoProcessor {
public static void getFruitInfo(Class<?> clazz){
String strName="fruit name: ";
String strColor="fruit color: ";
Field[] fields = clazz.getDeclaredFields();
for(Field field :fields){
if(field.isAnnotationPresent(FruitName.class)){
FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
strName = strName + fruitName.value();
System.out.println(strName);
} else if(field.isAnnotationPresent(FruitColor.class)){
FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);
strColor = strColor + fruitColor.fruitColor().toString();
System.out.println(strColor);
}
}
}
}
編譯期處理
總結(jié):Java注解的基礎(chǔ)知識(shí)點(diǎn)基本都過(guò)了一遍,最后用下面一張思維導(dǎo)圖總結(jié)