java基础-注解Annotation原理和用法
生活随笔
收集整理的這篇文章主要介紹了
java基础-注解Annotation原理和用法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載自?http://www.wolfbe.com/detail/201608/265.html
在很多java代碼中都可以看到諸如@Override、@Deprecated、@SuppressWarnings這樣的字符,這些就是注解Annotation。注解最早在jdk5中被引入,現在已經成為java平臺很重要的一部分了,很多的框架程序中也喜歡使用注解,如Spring、Mybatis等。
那么,什么是注解呢?注解就是元數據,一種描述數據的數據,通俗一點就是為程序的元素(類、方法、成員變量)加上更直觀的說明,這些說明信息是與程序的業務邏輯無關的。但是,我們可以通過java的反射機制來獲取Annotation的信息,并根據這些信息來對程序進行賦值、分發等操作。java5.0定義了4個標準的meta-annotation元注解,它們被用來提供對其它annotation類型作說明,四種元注解如下:
- @Target;
- @Retention;
- @Inherited;
- @Documented;
下面詳細說明這四種元注解的作用: @Target ? ? ?被用于描述注解的使用范圍,即注解可以用在所修飾對象的什么地方,取值可以是ElementType中的一種:
- CONSTRUCTOR:用于描述構造器;
- FIELD:用于描述域;
- LOCAL_VARIABLE:用于描述局部變量;
- METHOD:用于描述方法;
- PACKAGE:用于描述包;
- PARAMETER:用于描述參數;
- TYPE:用于描述類、接口、注解類型或枚舉;
@Target(ElementType.TYPE)
public @interface Exculde{/*** 名稱,默認值為""* @return*/public String name() default "";}
@Target(ElementType.FIELD)public @interface Inject{/*** id,默認值為""* @return*/public String id() default "";
/*** 類,默認值為""* @return*/public Class?clazz() default Object.class;}
上面定義了兩個注解,注解@Exculde只能用于修飾類、接口、注解、枚舉,注解@Inject只能修飾類型的域,如:
@Exculde(name="admin")public class User{@Inject(id="username",clazz=String.class)private String username;}
@Retention ? ? ?用于描述注解的生命周期,即注解能在源碼到JVM裝載過程中的哪一個級別上有效。有些annotation僅出現在源碼中,被編譯器丟棄;有些annotation能被編譯進class文件中,可能被JVM忽略;有些annotation不但能夠被編譯進class文件,而且能夠在class文件被裝載時被讀取。這三種情況對應RetentionPoicy的三種取值:
- SOURCE:源碼文件中保留;
- CLASS:class文件中保留;
- RUNTIME:運行時保留;
@Inherited ? ???用于描述注解是可以被繼承的,如果一個使用了@Inherited修飾的annotation被用于一個class,那么這個annotation也將被用于這個class的子類。@Inherited是一個標記注解,沒有參數選項,它修飾的annotation是被標記的class的子類所繼承,類并不從它所實現的接口繼承annotation,方法并不從它所重載的方法繼承annotation。 當使用java的反射去獲取一個@Inherited修飾的annotation時,反射檢查將遞歸檢查,檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。
@Documented 用于描述注解信息應該被作為被標注的程序的公共API,即應該把注解信息保留文檔中。@Documented也是一個標記注解,沒有參數選項。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface Exculde{/*** 名稱注解,默認值為""* @return
? ? */public String name() default "";}
如果你看過了上面的元注解,如果還不能理解也沒關系,下面我們通過自定義注解來進一步理解元注解。
自定義注解需要使用@interface,類似于定義一個類使用class,但定義注解時不能再繼承其它的類或者接口,它已經自動繼承了java.lang.annotation.Annotation接口。@interface用來聲明一個注解,其中的每一個方法實際上聲明了一個配置參數,方法的名稱就是參數的名稱,方法的返回值類型就是參數的類型,也可以使用default來聲明參數的默認值。
定義注解的格式如下: public @interface 注解名{ 定義體 }
注解參數可支持的數據類型如下:
- 基本類型;
- Class;
- String;
- Enum;
- Annotation;
- 以上所有類型的數組形式;
下面定義一個類似于Spring的注解,用于向實例對象注入屬性的值:
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Inject{/*** ID,默認值為""* @return*/public String id() default "";
/*** 類,默認值為""* @return*/public Class?clazz() default Object.class;
}
把@Inject標注在類UserAction的屬性上:
public class UserAction {@Inject(id="userService",clazz=UserService.class)private UserService userService;}
在IOC容器框架中,對象都會被自動初始化,如果我們要實現IOC的這種功能,我們應該為加上@Inject注解的屬性userService注入它的值。首先我們應該通過反射獲取userService的域對象field,通過field獲取@Inject注解的信息,然后根據注解的id和clazz得到它依賴的值:
Inject inject = field.getAnnotation(Inject.class);String id = inject.id();Class?clazz = inject.clazz();
Object userService = Class.forName(clazz.getName).newInstance();field.setAccessible(true);field.set(object,userService);
上面代碼中,調用field.getAnnotation(Inject.class)獲取到@Inject的對象,然后獲取@Inject的id和clazz值,通過反射實例化clazz的對象,再反射賦值給field。這就是Spring那些框架的依賴注入的實現原理,有興趣的可以自己再優化一下。
讀取類的注解信息還有其它的幾個方法,在此不再一一說明,可以自行研究java.lang.reflect包。經過上面的說明,由此我們也可以知道注解僅僅是一種元數據,增強類、屬性、參數的描述,使用注解的關鍵在于獲取注解的信息,再通過反射的手段來實現注解想達成的功能。
總結
以上是生活随笔為你收集整理的java基础-注解Annotation原理和用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 获取当前项目的类路径
- 下一篇: JVM系列之内存泄漏