1.Annotation是什麼?
註解是JDK5新增的,主要爲程序增加元數據。Annotation是一種接 口,主要用來對JAVA應用程序元素設置元數據。需要通過JAVA反射技術獲得Annotation對象,根據Annotation對象實例獲取程序元素上的元數據信息即Annotation信息。
2.如何定義Annotation?
定義註解Annotation很簡單,通過關鍵字@interface即可定義一個註解。下圖自定義一個註解。
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
// 作者
String author() default "tonny";
// 日期
String date();
}
3.哪些程序元素可以使用註解?
JAVA應用中哪些程序元素可以使用Annotation。在JDK中另外一個AnnotatedElement接口代表了程序中可以使用Annotation的程序元素,JDK中具體的實現類主要有:
3.1 Class:JAVA類從面可以使用註解Annotation.
3.2. Constructor:構造器可以使用註解Annotation。
3.3. Method:JAVA類中的方法可以使用註解Annotation
3.4. Field:JAVA類中的成員變量可以使用Annotation,Spring中 很多場景。
3.5. Package: 類的包定義上使用註解
4.註解特點
4.1.註解中可以定義方法,但都是無參的方法,即不能有任何參數。
4.2.註解中的方法可以有默認值,必須使用default 賦值。上述中,就是採用default進行賦值
4.3.註解中的方法名和返回類型就是註解中的成員變量名和變量類型
4.4.註解的返回類型只能是基本類型,String,枚舉類型,Annotation類型和這些類型組成的數組–非常重要
4.5.註解中如果定義成員變量,如果成員變量沒有默認值(即沒有使用default進行賦值),則在使用該註解時必須對成員變量進行賦值。
4.6.註解中可以包含元註解,元註解被用來定義自定義註解
5.四個元註解
JDK中提供了4個元數據註解,這4個元註解可以註解自定義註解
5.1@Target:
5.1.1.主要表明使用@Target註解的範圍,可以在哪些應用程序元素中使用。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
5.1.2.@Target的註解範圍通過ElementType枚舉類數組指定:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE
}
5.1.3.上述程序中是元註釋@Target源碼,可以發現@target包含元註解,通過該ElementType.ANNOTATION_TYPE指明瞭註解的範圍。
5.1.4.@Target註解的方法名爲value,即成員變量名。返回類型爲一個枚舉ElementType。符合註解中方法的返回類型要求(枚舉類型或枚舉類型數組)
5.1.5.通常情況下使用註解中的方法時,應該使用”name=value”形式。即 上述程序中@Target(ElementType.ANNOTATION_TYPE)
應該爲@Target(value = ElementType.ANNOTATION_TYPE)。如下情況特殊除外:
5.1.5.1如果自定義的註解中就含有一個成員變量而且成員變量的名稱爲value,則可以不需要使用name=value形式。
5.2@Retention
5.2.1使用@Retention修飾自定義的Annotation,表明該Annotation的聲明週期
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
5.2.2上述源碼錶明@Retention生命週期通過RetentionPolicy控制。RetentionPolicy爲枚舉類,主要包含3個數值:
5.2.2.1.RetentionPolicy.SOURCE:編譯器直接丟棄這種策略。
5.2.2.2.RetentionPolicy.CLASS:編譯器將Annotation記錄在CLASS文件中,但是JVM在運行時會拋棄。這也是默認行爲
5.2.2.3RetentionPolicy的源碼如下:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
5.3@Inherited
5.3.1@Inherited指定被它註解的Annotation將具有繼承性質,如果某 個類使用了自定義註解A(A註解被@Inherited修飾),則A的子類也具有A註解的特性。
5.3.2@Inherited的源碼如下,只是標記註解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
5.4@Documented
5.4.1.@Documented修飾的註解可以被javadoc工具文檔化。也是一個標記註解,源碼如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
6.自定義註解
6.1自定義註解只需要使用@interface聲明即可,如下定義了MethodInfo註解
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
// 作者
String author() default "tonny";
// 日期
String date();
// 版本
int version() default 1;
// 註釋
String comments();
}
6.2.定義了AnnotationExample類,使用自定義註解,如下
public class AnnotationExample {
@Override
@MethodInfo(author="tonny",date="2016-08-11",comments="override toString method")
public String toString(){
return "Override toString method";
}
@Deprecated
@MethodInfo(date="2016-08-11",comments="deprecated method")
public void oldMethod(){
System.out.println("deprecated method do not use it");
}
@SuppressWarnings(value = { "unchecked" })
@MethodInfo(date="2016-08-11",comments="deprecated method")
public List generateList(){
List l = new ArrayList();
l.add("a");
l.add("b");
return l;
}
}
6.3.類AnnotationParse.java是一個簡單的解析註解的小程序:
public class AnnotationParse {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Method[] methods = AnnotationParse.class.getClassLoader()
.loadClass("com.egfbank.annotaion.example1.AnnotationExample")
.getMethods();
for(Method m:methods){
// getAnnotations()返回指定元素上所有的註釋
for(Annotation anno : m.getAnnotations()){
System.out.println("annotation : "+anno);
}
//檢查 註解MethodInfo是否起到作用
// 判斷程序中指定元素上某個特定的註釋是否存在
if(m.isAnnotationPresent(MethodInfo.class)){
MethodInfo ma = m.getAnnotation(MethodInfo.class);
System.out.println(ma.author());
System.out.println(ma.date());
}
}
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
7.總結
7.1通過上述例子,可以看出註解必須和反射技術結合起來才能發揮重要的作用。靈活使用註解可以減少很多無用的代碼的編寫。