最近在研究阿里開源的ARouter框架冻记,碰到了較多注解的使用。結合ButterKnife開源框架的使用来惧,越來越體會到熟練使用注解的重要性冗栗。故針對注解再次進行學習和總結,重要的是輔助代碼來驗證。
Annotation注解
Annontation是Java5開始引入的新特征隅居,中文名稱叫注解钠至。它提供了一種安全的類似注釋的機制,用來將任何的信息或元數(shù)據(jù)(metadata)與程序元素(類胎源、方法棉钧、成員變量等)進行關聯(lián)。為程序的元素(類涕蚤、方法宪卿、成員變量)加上更直觀更明了的說明,這些說明信息是與程序的業(yè)務邏輯無關赞季,并且供指定的工具或框架使用愧捕。Annontation像一種修飾符一樣,應用于包申钩、類型、構造方法、方法、成員變量散罕、參數(shù)及本地變量的聲明語句中完箩。
Java注解是附加在代碼中的一些元信息,用于一些工具在編譯纠吴、運行時進行解析和使用,起到說明、配置的功能廉涕。注解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用艇拍。包含在 java.lang.annotation 包中狐蜕。
JDK內(nèi)置注解
常用的標準注解有:
- @Override,主要用于在子類中覆蓋父類中的方法
- @Deprecated卸夕,用來標志被棄用的代碼层释,編譯器會進行警告
-
@SuppressWarnings,用于忽略編譯器的警告信息快集。
相信大家在日常工作中經(jīng)常使用以上三種注解贡羔。
元注解
開發(fā)人員可以根據(jù)自己的需要自定義注解,這時需要用到@Retention, @Target, @Inherited, @Documented這幾個元注解个初。
- @Rentention定義注解的保留級別乖寒。取值范圍是RetentionPolicy類型,源碼定義如下:
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
}
包括SOURCE:在代碼編寫階段存在院溺,編譯時被丟棄楣嘁。如@Override
CLASS:編譯階段注解保留在class文件中,VM運行時不需要保留。一般用來動態(tài)生成java代碼马澈,如ARouter瓢省,ButterKnife框架
RUNTIME:編譯階段注解保留在class文件中,VM運行時仍保留注解痊班。一般與反射結合使用勤婚,如Retrofit。
- @Target定義注解可以用于什么對象涤伐。取值范圍是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,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
其中常用的類型有TYPE:類、接口(包括注解)凝果、枚舉
FIELD:成員變量
METHOD:成員方法
PARAMETER:方法參數(shù)
ANNOTATION_TYPE:注解的注解
@Documented標志注解將包含在Javadoc中
@Inherited允許子類繼承父類中的注解
關于每種元注解的具體定義祝迂,可以在Android Studio中方便的查看源碼文件。reading the fuck code!
自定義注解
開發(fā)人員可以使用上面的元注解來定義自己的注解器净。示例如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeAnno {
String value();
boolean isAlive() default false;
}
使用@interface定義注解型雳,類名即為注解名。自定義注解中只能定義方法山害,所有的方法均沒有參數(shù)纠俭,也沒有修飾符(默認是public&abstract修飾符),方法的返回值是基本類型浪慌、String冤荆、Classs、Annotation权纤、Enum或者對應的一位數(shù)組钓简。方法可以通過default設置默認值汹想。
注解使用時,如果只有一個方法欧宜,則可直接“注解名(值)”來使用坐榆;如果有多個方法冗茸,則需要依次賦值“注解名(方法名=值,方法名=值...)”夏漱。如果方法使用default賦值,則不必在使用時顯示賦值挂绰。
@RuntimeAnno(value="11111")
@RuntimeAnno("22222")
@RuntimeAnno(value="33333", isAlive = true)
典型的注解定義如下圖:
其中服赎,ButterKnife的OnClick注解使用了自定義注解ListenerClass交播,具體定義可參考ButterKnife源碼。
運行時(RUNTIME)注解的解析
以Method為例秦士,參考Method的源碼缺厉,可以看到有如下幾個方法:
/**
* {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @since 1.5
*/
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return super.getAnnotation(annotationClass);
}
/**
* {@inheritDoc}
* @since 1.5
*/
public Annotation[] getDeclaredAnnotations() {
return super.getDeclaredAnnotations();
}
/**
* {@inheritDoc}
* @since 1.5
*/
@Override
public Annotation[][] getParameterAnnotations() {
// Android-changed: This is handled by Executable.
return super.getParameterAnnotationsInternal();
}
其中getAnnotation(AnnotationName.class) 可獲取該 Target 某個 Annotation 的信息;因為一個 Target 可以被多個 Annotation 修飾.
getAnnotations() 則可獲取該 Target 所有 Annotation. getParameterAnnotations可以獲取方法的所有參數(shù)的注解隧土,返回值是一個二維數(shù)組提针。
其他Target,如Filed曹傀,Class辐脖,獲取Annotation的方法可參考java源碼。
高版本的jdk還有isAnnotationPresent(AnnotationName.class) 方法皆愉,來判斷Target 是否被某個 Annotation 修飾嗜价。
編譯時(CLASS)注解解析
編譯器解析編譯時注解,需要做的是1亥啦、自定義類繼承AbstractProcessor炭剪;2、重寫process函數(shù)翔脱。具體使用方法,可參考網(wǎng)上的其他文檔媒鼓。
ButterKnife就是使用編譯時注解届吁,生成JAVA文件。
注解的作用
1绿鸣、JDK標準注解疚沐,可用來生成JavaDoc,如@param @return潮模;可用來進行代碼檢查亮蛔,如@Override,@Deprecated擎厢。
2究流、目前較多框架使用注解,來自動生成代碼或替代配置文件的功能动遭。注解可以使編碼更簡潔芬探,學習注解可以理解使用開源框架,甚至自定義框架來解決問題厘惦。
3偷仿、注解和反射配合使用,可以使用簡潔的代碼實現(xiàn)復雜的功能,筆者目前的網(wǎng)絡庫入?yún)⒕筒捎昧俗⒔庠途玻瑒討B(tài)代理和反射技術节榜。可以參考反射注解與動態(tài)代理綜合使用别智,該文檔寫的簡單易懂宗苍。
參考文檔:
注解Annotation實現(xiàn)原理與自定義注解例子
反射注解與動態(tài)代理綜合使用
框架開發(fā)之Java注解的妙用