目前主流框架都支持注解。比如Android平臺上的 Retrofit,EventBus,Butterknife等
Java Web: Spring MVC ,MyBatis等.注解是從Java SDK 1.5 開始啟動使用的,使用注解到底有什么好處呢?
對于配置文件需要添加較多邏輯代碼來處理,而注解只需要注解元 數據就可以區分,代碼整潔,閱讀性好,減少配置文件等。
如上圖所示:
Java的注解分為元注解和標準注解。
- 標準注解:系統提供的注解
@Deprecated :表示已經過期,不推薦使用.比如你有一個方法現在不想用了,但是其他人調用了,刪掉會影響其他代碼。這樣用這個標記來說明.
@Documented
@Retention(RetentionPolicy.RUNTIME)//運行期runtime
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})//范圍
public @interface Deprecated {
}
@Deprecated
public void test(){
}
@Override 主要作用是覆蓋父類方法
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)//在源文件中出現,在編譯后會被編譯器丟棄
public @interface Override {
}
比如android onCreate方法,覆蓋父類方法
@Override
protected void onCreate(Bundle savedInstanceState) {
}
比如java toString()方法,覆蓋java lang toString方法
@Override
public String toString() {
return super.toString();
}
@SupressWarning 關閉不當的編譯器警告信息
比如
- 元注解:可以自己定義注解
@Retention 表示需要在什么級別保存該注解信息,標記有下面3個參數可選
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,//注解在class文件可用,但是會VM丟棄
/**
* 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//VM運行期也會保留注解,可用用反射機制可用讀取對應的數據
}
@Target 表示被描述的注解用于什么地方,可用運用到地方如下
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();//這邊是一個ElementType數組
}
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,//用于描述類,接口 或枚舉聲明
/** Field declaration (includes enum constants) */
FIELD,//用于描述域
/** Method declaration */
METHOD,//用于描述方法
/** Formal parameter declaration */
PARAMETER,//用于描述參數
/** Constructor declaration */
CONSTRUCTOR,//用于描述構造器
/** Local variable declaration */
LOCAL_VARIABLE,//用于描述局部變量
/** Annotation type declaration */
ANNOTATION_TYPE,//用于描述Annotation type
/** Package declaration */
PACKAGE,//描述包
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
@Documented用于描述其它類型的annotation應該被作為被標注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是一個標記注解,沒有成員.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
@Inherited 元注解是一個標記注解,@Inherited闡述了某個被標注的類型是被繼承的,則這個annotation將被用于該class的子類。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
自定義自己的Annotation 格式如下
public @interface 注解名 {定義體}
定義體里面一般如下圖所示:
舉個栗子寫個Demo吧:
定義一個Person Annotation 里面定義了2個方法 say 和move 方法.
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.LOCAL_VARIABLE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonAnnotation {
public String say() default "hello";
public String move() default "walk";
Sex sex() default Sex.MAN;//枚舉類型
}
定義一個UserAnnotation 定義name, age 和 PersonAnnotation annotation
@Target({ElementType.METHOD , ElementType.TYPE,ElementType.FIELD,ElementType.LOCAL_VARIABLE})//可以修飾方法,實例變量,local 變量
@Retention(RetentionPolicy.RUNTIME)
public @interface UserAnnotation {
String name() default "";
String age() default "";
PersonAnnotation person();//使用了Annotation類型
}
定義性別enum.
public enum Sex {
MAN,WOMEN,OTHER
}
上面的代碼定義的不錯,那怎么使用呢?答案是反射,直接上代碼吧??
定義User類
@UserAnnotation//因為在Target定義了ElementType.TYPE可以修飾類
public class User {
@UserAnnotation(name = "Star")//因為在Target中定義了ElementType.FIELD就可以定義在實例變量中拉
protected String name;
@UserAnnotation(age = 100)
int age;
@UserAnnotation(name = "wong" , age = 1000)
protected String value;
@UserAnnotation(name = "GEAK",age = 90)//因為在Target中定義了ElementType.METHOD
public void getUserInfo(String name,int age){
System.out.println("the name is:"+name+"\tthe age is:"+age);
}
public void getInfo(){
System.out.println("=======getInfo start=====");
System.out.println("the name is:"+this.name+"\tthe age is:"+this.age);
System.out.println("=======getInfo end=====");
}
}
定義了自己的元數據,下面是測試怎么使用
@Test
public void test() {
//User user = new User();
System.out.println("startTest");
Class<User> u = User.class;
try {
Method method = u.getMethod("getUserInfo", new Class[]{String.class, int.class});
UserAnnotation userAnnotation = method.getAnnotation(UserAnnotation.class);
System.out.println("the name is:" + userAnnotation.name() + "the age is:" + userAnnotation.age());
if (method != null) {
method.invoke(u.newInstance(), userAnnotation.name(), userAnnotation.age());
}
Field fields[] = u.getDeclaredFields();
Field f = u.getDeclaredField("value");
UserAnnotation userAnnotation1 = f.getAnnotation(UserAnnotation.class);
System.out.println("the f name is:" + userAnnotation1.name() + "the f age is:" + userAnnotation1.age());
for (Field field : fields) {
if (field.isAnnotationPresent(UserAnnotation.class)) {
System.out.println("the name is:" + field.getName());
UserAnnotation annotation = field.getAnnotation(UserAnnotation.class);
if (annotation != null) {
System.out.println("the name is:" + annotation.name() + "the age is:" + annotation.age());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
獲取對應的User Class ,有下面兩種方式
獲取Class相關
1.Class<User> u = User.class; //通過Class直接獲取
2.Class<User> u = Class.forName("User");//通過name獲取Class中主要用到的方法
Method[] getMethods() //獲取所有的方法包括父類的方法
Field[] getFields() //獲取所有實例變量包括父類的實例
Field[] getDeclaredFields()//獲取所有的方法不包括父類的方法
Method[] getDeclaredMethods()//獲取所有實例變量不包括父類的實例獲取Annotation
Method.getAnnotation(Annatation.class)//獲取方法上面的Annotation
Field.getAnnotation(Annatation.class)//獲取filed上的Annotation
獲取結果:
the name is:GEAKthe age is:90 //獲取到方法上的Annotation
the name is:GEAK the age is:90//獲取到方法上的Annotation
the f name is:wongthe f age is:1000//利用反射的機制來調用方法
the name is:name
the name is:Starthe age is:10//獲取對應實例的name上的Annotation
the name is:age
the name is:the age is:100
the name is:value
the name is:wongthe age is:1000
總結:
通過Annotation和反射機制來進行合理的配置你的源代碼.這樣就可以省去大部分的if else或者初始化等工作.