一村砂、注解的概念
注解(Annotation),也叫元數(shù)據(jù)(Metadata)屹逛。注解與類础废、接口、枚舉在同一個(gè)層次罕模,并可以應(yīng)用于包评腺、類型、構(gòu)造方法手销、方法歇僧、成員變量、參數(shù)锋拖、本地變量的聲明中诈悍,用來對(duì)這些元素進(jìn)行說明注釋。
注解分類
基本內(nèi)置注解兽埃,是指Java自帶的幾個(gè)Annotation侥钳,如@Override、Deprecated柄错、@SuppressWarnings等舷夺;
元注解(meta-annotation)苦酱,是指負(fù)責(zé)注解其他注解的注解,包含如下四個(gè):
@Target
@Retention
@Documented
@Inherited
- 自定義注解给猾,需要用到上面的元注解
二疫萤、注解的語法與定義形式
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.ANNOTATION_TYPE } )
public @interface Target {
ElementType[] value();
}
- 元注解@Retention,標(biāo)明生命周期敢伸。
- 元注解@Target扯饶,標(biāo)明修飾目標(biāo)
- 成員名稱為value,類型為ElementType[]
- 如果成員名稱是value池颈,在賦值過程中可以簡(jiǎn)寫尾序。如果成員類型為數(shù)組,但是只賦值一個(gè)元素躯砰,則也可以簡(jiǎn)寫每币。
eg:
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface RouterMap {
String value();
String[] registry() default {};
}
// 使用
@RouterMap(value = "HHH://XXX", registry = {"110"})
public class DownloadActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
}
}
元注解說明
1、@Retention : 注解的生命周期
注解的值是 enum 類型的 RetentionPolicy琢歇,包括以下幾種情況:
public enum RetentionPolicy {
/**
* 注解只保留在源文件兰怠,當(dāng)Java文件編譯成class文件的時(shí)候,注解被遺棄.
* 這意味著:Annotation僅存在于編譯器處理期間李茫,編譯器處理完之后痕慢,該Annotation就沒用了
*/
SOURCE,
/**
* 注解被保留到class文件,但jvm加載class文件時(shí)候被遺棄涌矢,這是默認(rèn)的生命周期.
*/
CLASS,
/**
* 注解不僅被保存到class文件中掖举,jvm加載class文件之后,仍然存在娜庇,
* 保存到class對(duì)象中塔次,可以通過反射來獲取
*/
RUNTIME
}
這3個(gè)生命周期分別對(duì)應(yīng)于:Java源文件(.java文件) ---> .class文件 ---> 內(nèi)存中的字節(jié)碼。
首先要明確生命周期長(zhǎng)度 SOURCE < CLASS < RUNTIME 名秀,所以前者能作用的地方后者一定也能作用励负。一般如果需要在運(yùn)行時(shí)去動(dòng)態(tài)獲取注解信息,那只能用 RUNTIME 注解匕得;如果要在編譯時(shí)進(jìn)行一些預(yù)處理操作继榆,比如生成一些輔助代碼(如 ButterKnife),就用 CLASS注解汁掠;如果只是做一些檢查性的操作略吨,比如 @Override 和 @SuppressWarnings,則可選用 SOURCE 注解考阱。
2翠忠、@Documented和@Inherited
@Documented:標(biāo)記注解,如javadoc此類的工具文檔化乞榨。
@Inherited:標(biāo)記注解秽之,允許子類繼承父類的注解
3当娱、@Target
標(biāo)明注解的修飾目標(biāo),共有
// ElementType取值
public enum ElementType {
/** 類考榨、接口(包括注解類型)或枚舉 */
TYPE,
/** field屬性跨细,也包括enum常量使用的注解 */
FIELD,
/** 方法 */
METHOD,
/** 參數(shù) */
PARAMETER,
/** 構(gòu)造函數(shù) */
CONSTRUCTOR,
/** 局部變量 */
LOCAL_VARIABLE,
/** 注解上使用的元注解 */
ANNOTATION_TYPE,
/** 包 */
PACKAGE
}
三、@Retention使用場(chǎng)景:
1河质、RetentionPolicy.SOURCE
考慮我們平時(shí)會(huì)遇到的一種情況:
我們定義的類有一個(gè) int 型的狀態(tài)參數(shù)要設(shè)置扼鞋,但我們?cè)O(shè)置的狀態(tài)又只能限定在[TYPE_UNDERSCORE = 0, TYPE_BACKGROUND = 1]這兩種狀態(tài),如果我們要提供一個(gè)接口來設(shè)置的話愤诱,那么一種做法是定義一個(gè)Enum枚舉來作為參數(shù),這樣就能限定參數(shù)的取值范圍了捐友,但是使用枚舉會(huì)比常量占用更多的內(nèi)存淫半。
這里可以用注解來處理這種問題,也就是下面要講的自定義源碼注解匣砖,這里需要用到一個(gè)元注解@IntDef科吭,
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.PARAMETER)
@IntDef({PageTabSelectedType.TYPE_UNDERSCORE, PageTabSelectedType.TYPE_BACKGROUND})
public @interface PageTabSelectedType {
// 下劃線選中模式
int TYPE_UNDERSCORE = 0;
// 背景選中模式
int TYPE_BACKGROUND = 1;
}
public void setSelectedType(@PageTabSelectedType int selectedType){
mSelectedType = selectedType;
}
這樣在使用調(diào)用方法的使用只能使用指定的參數(shù),就算用數(shù)值2猴鲫,編譯器也會(huì)提示報(bào)錯(cuò)对人。除了@IntDef注解外還用一個(gè)@StringDef注解可以使用,用來處理字符串拂共。
2牺弄、RetentionPolicy.RUNTIME
一般如果需要在運(yùn)行時(shí)去動(dòng)態(tài)獲取注解信息,那只能用 RUNTIME 注解宜狐,此時(shí)注解不僅被保存到class文件中势告,jvm加載class文件之后,仍然存在抚恒,可以通過反射的方式獲取運(yùn)行時(shí)注解咱台。
/**
* 獲取指定類型的注解
*/
public <A extends Annotation> A getAnnotation(Class<A> annotationType);
/**
* 獲取所有注解,如果有的話
*/
public Annotation[] getAnnotations();
/**
* 獲取所有注解俭驮,忽略繼承的注解
*/
public Annotation[] getDeclaredAnnotations();
/**
* 指定注解是否存在該元素上回溺,如果有則返回true,否則false
*/
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
/**
* 獲取Method中參數(shù)的所有注解
*/
public Annotation[][] getParameterAnnotations();