Android編譯時注解框架系列1

Java注解(annotation)

什么是注解?

定義:注解(Annotation),也叫元數據试伙。一種代碼級別的說明嘁信。它是JDK1.5及以后版本引入的一個特性于样,與類、接口潘靖、枚舉是在同一個層次穿剖。它可以聲明在包、類卦溢、字段糊余、方法、局部變量单寂、方法參數等的前面贬芥,用來對這些元素進行說明,注釋宣决。

Annotation是被動的元數據蘸劈,永遠不會有主動行為
既然是被動數據,對于那些已經存在的注解尊沸,比如Override,我們只能看看而已威沫,并不知道它具體的工作機制是什么;所以想要理解注解洼专,就直接從自定義注解開始棒掠。

自定義注解

下面是一段代碼示例,具體每個代碼功能下面會講到:

    //用來標記自定義注解的有效范圍
    @Retention(RetentionPolicy.RUNTIME)
    //指定Annotation用于修飾哪些程序元素
    @Target({ElementType.TYPE})
    //用于描述其它類型的annotation應該被作為被標注的程序成員的公共API
    @Documented
    //元注解是一個標記注解屁商,@Inherited闡述了某個被標注的類型是被繼承的
    @Inherited
    public @interface ContentView {//@interface表明這是一個注解
        int value() default -1;
    }

元注解:
  元注解的作用就是負責注解其他注解烟很。Java5.0定義了4個標準的meta-annotation類型,它們被用來提供對其它 annotation類型作說明棒假。Java5.0定義的元注解:

1.@Target,    
2.@Retention,    
3.@Documented,    
4.@Inherited  

這些類型和它們所支持的類在java.lang.annotation包中可以找到溯职。下面我們看一下每個元注解的作用和相應分參數的使用說明。

@Target:
   @Target說明了Annotation所修飾的對象范圍:Annotation可被用于 packages帽哑、types(類、接口叹俏、枚舉妻枕、Annotation類型)、類型成員(方法粘驰、構造方法屡谐、成員變量、枚舉值)蝌数、方法參數和本地變量(如循環(huán)變量愕掏、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標顶伞。
  作用:用于描述注解的使用范圍(即:被描述的注解可以用在什么地方)
  取值(ElementType)有:

1.CONSTRUCTOR:用于描述構造器    
2.FIELD:用于描述域    
3.LOCAL_VARIABLE:用于描述局部變量    
4.METHOD:用于描述方法    
5.PACKAGE:用于描述包    
6.PARAMETER:用于描述參數    
7.TYPE:用于描述類饵撑、接口(包括注解類型) 或enum聲明

@Retention:
  @Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在源代碼中剑梳,而被編譯器丟棄;而另一些卻被編譯在class文件中滑潘;編譯在class文件中的Annotation可能會被虛擬機忽略垢乙,而另一些在class被裝載時將被讀取(請注意并不影響class的執(zhí)行语卤,因為Annotation與class在使用上是被分離的)追逮。使用這個meta-Annotation可以對 Annotation的“生命周期”限制。
  作用:表示需要在什么級別保存該注釋信息粹舵,用于描述注解的生命周期(即:被描述的注解在什么范圍內有效)
  取值(RetentionPoicy)有:
    
1.SOURCE:在源文件中有效(即源文件保留)    
2.CLASS:在class文件中有效(即class保留)    
3.RUNTIME:在運行時有效(即運行時保留)

Retention meta-annotation類型有唯一的value作為成員钮孵,它的取值來自java.lang.annotation.RetentionPolicy的枚舉類型值。

@Documented:
 @Documented 用于描述其它類型的annotation應該被作為被標注的程序成員的公共API眼滤,因此可以被例如javadoc此類的工具文檔化油猫。Documented是一個標記注解,沒有成員

@Inherited:
 @Inherited  元注解是一個標記注解柠偶,@Inherited闡述了某個被標注的類型是被繼承的情妖。如果一個使用了@Inherited修飾的annotation類型被用于一個class,則這個annotation將被用于該class的子類诱担。
  注意:@Inherited annotation類型是被標注過的class的子類所繼承毡证。類并不從它所實現的接口繼承annotation,方法并不從它所重載的方法繼承annotation蔫仙。
  當@Inherited annotation類型標注的annotation的Retention是RetentionPolicy.RUNTIME料睛,則反射API增強了這種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時摇邦,反射代碼檢查將展開工作:檢查class和其父類恤煞,直到發(fā)現指定的annotation類型被發(fā)現,或者到達類繼承結構的頂層施籍。

自定義注解:
  使用@interface自定義注解時居扒,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細節(jié)丑慎。在定義注解時喜喂,不能繼承其他的注解或接口。@interface用來聲明一個注解竿裂,其中的每一個方法實際上是聲明了一個配置參數玉吁。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型腻异、Class进副、String、enum)悔常∮鞍撸可以通過default來聲明參數的默認值给赞。
  定義注解格式:  public @interface 注解名 {定義體}
  ****注解參數的可支持數據類型:

1.所有基本數據類型(int,float,boolean,byte,double,char,long,short)    2.String類型    
3.Class類型    
4.enum類型    
5.Annotation類型    
6.以上所有類型的數組

Annotation類型里面的參數該怎么設定:

第一,只能用public或默認(default)這兩個訪問權修飾.例如,String value();這里把方法設為defaul默認類型;     
第二,參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和 String,Enum,Class,annotations等數據類型,以及這一些類型的數組.例如,String value();這里的參數成員就為String;    
第三,如果只有一個參數成員,最好把參數名稱設為"value",后加小括號.

     //注解解析
    //一下步驟可以在base基類完成
    //        for (Class c = this.getClass(); c != Context.class; c = c.getSuperclass()) {
                ContentView annotation = this.getClass().getAnnotation(ContentView.class);
                if (annotation != null) {
                    try {
                        this.setContentView(annotation.value());
                    } catch (RuntimeException e) {
                        e.printStackTrace();
                    }
                    return;
    //            }
            }

第一步:遍歷所有的子類
第二步:找到修飾了注解ContentView的類
第三步:獲取ContentView的屬性值鸥昏。
第四步:為Activity設置布局塞俱。

總結
你可能會覺得setContentView(R.layout.activity_home)@ContentView(R.layout.activity_home)沒什么區(qū)別,用了注解反而還增加了性能問題吏垮。

但你要知道障涯,這只是注解最簡單的應用方式。舉一個例子:AndroidEventBus的注解是運行時注解膳汪,雖然會有一點性能問題唯蝶,但是在開發(fā)效率上是有提高的。

注意

很多人會問遗嗽,在java代碼中利用反射會不會對app性能產生影響粘我,答案是肯定的,但是有解決的辦法呢痹换,就是這個 Java Annotation Processing

Annotation processing 是javac中用于編譯時掃描和解析Java注解的工具征字。Annotation processing是在編譯階段執(zhí)行的,它的原理就是讀入Java源代碼娇豫,解析注解匙姜,然后生成新的Java代碼。新生成的Java代碼最后被編譯成Java字節(jié)碼冯痢,注解解析器(Annotation Processor)不能改變讀入的Java 類氮昧,比如不能加入或刪除Java方法

這樣性能的問題就解決了呢

詳細資料參考這里哦

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浦楣,隨后出現的幾起案子袖肥,更是在濱河造成了極大的恐慌,老刑警劉巖振劳,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎组,死亡現場離奇詭異,居然都是意外死亡澎迎,警方通過查閱死者的電腦和手機庐杨,發(fā)現死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夹供,“玉大人,你說我怎么就攤上這事仁堪∠ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵弦聂,是天一觀的道長鸟辅。 經常有香客問我氛什,道長,這世上最難降的妖魔是什么匪凉? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任枪眉,我火速辦了婚禮,結果婚禮上再层,老公的妹妹穿的比我還像新娘贸铜。我一直安慰自己,他們只是感情好聂受,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布蒿秦。 她就那樣靜靜地躺著,像睡著了一般蛋济。 火紅的嫁衣襯著肌膚如雪棍鳖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天碗旅,我揣著相機與錄音渡处,去河邊找鬼。 笑死祟辟,一個胖子當著我的面吹牛医瘫,可吹牛的內容都是我干的。 我是一名探鬼主播川尖,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼登下,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了叮喳?” 一聲冷哼從身側響起被芳,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎馍悟,沒想到半個月后畔濒,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡锣咒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年侵状,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毅整。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡趣兄,死狀恐怖,靈堂內的尸體忽然破棺而出悼嫉,到底是詐尸還是另有隱情艇潭,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蹋凝,受9級特大地震影響鲁纠,放射性物質發(fā)生泄漏。R本人自食惡果不足惜鳍寂,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一改含、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧迄汛,春花似錦捍壤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至硬霍,卻和暖如春帜慢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唯卖。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工粱玲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拜轨。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓抽减,卻偏偏與公主長得像,于是被迫代替她去往敵國和親橄碾。 傳聞我的和親對象是個殘疾皇子卵沉,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內容