Java注解(Annotation)詳解

Java注解(Annotation)詳解

1.Annotation的概念

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

  • 注解是一種可以添加到Java源代碼的元數(shù)據(jù).
  • 類,方法,變量,參數(shù),包都可以被注解.
  • 注解對注解的代碼并沒有直接的影響.
  • 注解僅僅是個(gè)標(biāo)記.注解之所以起作用是對其解析后做了相應(yīng)的處理

2.Annotation分類

  • 標(biāo)準(zhǔn)Annotation
    • 標(biāo)準(zhǔn)Annotation是指Java內(nèi)置的三個(gè)Annnotaion:
    • @Override:用于修飾此方法覆蓋了父類的方法.
    • @Deprecated:用于修飾已經(jīng)過時(shí)的方法.
    • @SuppressWarnnings:用于通知java編譯器禁止特定的編譯警告.
  • 元Annotation(注解的注解)
    • 元Annotation是用來定義Annotation的Annotation
    • 元Annotation可以定義Annotation的作用范圍,使用在什么元素上等
    • 元注解共有四種@Retention, @Target, @Inherited, @Documented
  • 自定義Annotation

3.元Annotation

  • @Retention:注在其他的注解A上,用來說明A的保留范圍,可選值 SOURCE(源碼時(shí))稚照,CLASS(編譯時(shí))撵颊,RUNTIME(運(yùn)行時(shí))彬坏,默認(rèn)為 CLASS
    • SOURCE:A只保留在源碼中,A會(huì)被編譯期忽略.(源碼可用)
    • CLASS:A會(huì)通過編譯保存在CLASS文件中,但會(huì)被JVM在運(yùn)行時(shí)忽略,運(yùn)行時(shí)不可見.(源碼+CLASS可用)
    • RUNTIME:A會(huì)被JVM獲取,并在運(yùn)行時(shí)通過反射獲取.(源碼+CLASS+運(yùn)行時(shí)均可用)
  • @Target:注在其他的注解A上,用來限制A可用修飾那些程序元素.未標(biāo)注Target表示無限制,可修飾所有元素.
    • ANNOTATION_TYPE: A可以應(yīng)用到其他注解上
    • CONSTRUCTOR: A可以使用到構(gòu)造器上
    • FIELD: A可以使用到域或?qū)傩陨?/li>
    • LOCAL_VARIABLE: A可以使用到局部變量上。
    • METHOD: A可以使用到方法上冒黑。
    • PACKAGE: A可以使用到包聲明上。
    • PARAMETER: A可以使用到方法的參數(shù)上
    • TYPE: A可以使用到類,接口(包括注解),或枚舉的聲明上
  • @Inherited:默認(rèn)情況下,父類的注解不會(huì)被子類繼承.
    • Inherited注在其他的注解A上.
    • 只有當(dāng)A是注解在類Class上面,Inherited才會(huì)起作用,其他任何情況下無效果.
    • 當(dāng)A注解在類C上面,則C的所有子孫類,都會(huì)繼承應(yīng)用A注解;
  • @Documented:注在其他的注解A上,A將會(huì)作為Javadoc產(chǎn)生的文檔中的內(nèi)容疙咸。注解都默認(rèn)不會(huì)成為成為文檔中的內(nèi)容尤蛮。

4.自定義Annotation

  1. 創(chuàng)建自定義Annotation流程

    • public @interface 自定義注解名稱
      public @interface CustomAnnotation{***}
          
      
    • 設(shè)置自定義Annotation的保留范圍和目標(biāo),Retention和Target是最重要的兩個(gè)元Anitation.
      @Retention( RetentionPolicy.RUNTIME )
      @Target( ElementType.TYPE )
      public @interface CustomAnnotation{***}
      
    • 設(shè)置自定義Annotation的注解參數(shù)(注解成員)
      • 注解參數(shù)支持的數(shù)據(jù)類型
        • 所有基本數(shù)據(jù)類型(int,float,boolean,byte,double,char,long,short)
        • String類型
        • Class類型
        • enum類型
        • Annotation類型
        • 以上所有類型的一維數(shù)組
      • 注解參數(shù)聲明方式
        @Retention( RetentionPolicy.RUNTIME )
        @Target( ElementType.TYPE )
        public @interface CustomAnnotation{
            //注解參數(shù)類型可以是1-6中任一種,包括枚舉
            public enum Skill{JAVA,ANDROID,IOS}
            Skill mySkill() default Skill.ANDROID;
            String attr1();
            //可以使用default設(shè)置默認(rèn)值
            int attr2() default 100;
            //修飾符只能用public
            public boolean attr3() default false;
        }
        @Retention( RetentionPolicy.RUNTIME )
        @Target( ElementType.TYPE )
        public @interface CustomAnnotation{
            //只有一個(gè)注解參數(shù),使用value()
            String value();
        }
        
        • 自定義Annotation的參數(shù)類型必須滿足上一條1到6中的范圍.
        • 自定義Annotation的參數(shù)訪問方法只能是public,或不寫.
        • 自定義Annotation的參數(shù)可以加 default 設(shè)置默認(rèn)值.
        • 自定義Annotation若只有1個(gè)參數(shù),使用value().
  2. 自定義Annotation的注解參數(shù)的默認(rèn)值

    注解元素必須有確定的值媳友,要么在定義注解的默認(rèn)值中指定,要么在使用注解時(shí)指定抵屿,非基本類型的注解元素的值不可為null庆锦。因此, 使用空字符串或0作為默認(rèn)值是一種常用的做法捅位。這個(gè)約束使得處理器很難表現(xiàn)一個(gè)元素的存在或缺失的狀態(tài)轧葛,因?yàn)槊總€(gè)注解的聲明中,所有元素都存在艇搀,并且都具有相應(yīng)的值尿扯,為了繞開這個(gè)約束,我們只能定義一些特殊的值焰雕,例如空字符串或者負(fù)數(shù)衷笋,一次表示某個(gè)元素不存在,在定義注解時(shí)矩屁,這已經(jīng)成為一個(gè)習(xí)慣用法辟宗。

    示例:
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AnotherAnnotation{
        String author() default "";
        int age() default -1;
    }
    
  3. 使用剛剛創(chuàng)建的自定義注解

    @CustomAnnotation(attr1 = "屬性1", attr2 = 90, attr3 = true)
    public class AnnotationTestClass{
        ***
    }
    

5.Annotation解析

  • 運(yùn)行時(shí) Annotation 解析

    運(yùn)行時(shí) Annotation 指 @Retention 為 RUNTIME 的 Annotation
    - Class,Method,Field中都有以下3個(gè)方法可以調(diào)用
    - public <T extends Annotation> T getAnnotation(Class<T> annotationClass) 按照傳入的參數(shù)獲取指定類型的注解。返回null說明當(dāng)前元素不帶有此注解吝秕。
    - public final boolean isAnnotationPresent(Class<? extends Annotation> annotationType) 檢查傳入的注解是否存在于當(dāng)前元素泊脐。
    - public Annotation[] getAnnotations() 返回該元素的所有注解,包括沒有顯式定義該元素上的注解烁峭。
    - 運(yùn)行時(shí) Annotation 解析示例
    public void testCustomAnnotation() { try { Class cls = Class.forName("com.jet.annotation.AnnotationTestClass"); CustomAnnotation customAnnotation = (CustomAnnotation)cls.getAnnotation(CustomAnnotation.class); System.out.println("customAnnotation mySkill:" + cus.mySkill()); System.out.println("customAnnotation attr1:" + cus.attr1()); System.out.println("customAnnotation attr2:" + cus.attr2()); } catch (ClassNotFoundException e) { e.printStackTrace(); } }

  • 編譯時(shí) Annotation 解析

    編譯時(shí) Annotation 指 @Retention 為 CLASS 的 Annotation容客,甴編譯器自動(dòng)解析


6.編譯時(shí)Annotation解析

編譯時(shí)Annotation解析 相對復(fù)雜,下面單獨(dú)進(jìn)行分析

首先申明:下面內(nèi)容僅僅討論 編譯時(shí)Annotation的解析

  1. 編譯時(shí)Annotation的解析,是由Annotation Processor完成
  2. Annotation Processor(注解處理器)
    • 注解處理器是一個(gè)在javac中的,用來在編譯時(shí)掃描和處理注解的工具
    • 我們可以為特定的注解,注冊自定義的注解處理器
    • 在編譯期間,JVM會(huì)自動(dòng)運(yùn)行注冊過的注解處理器
    • 一個(gè)注解的Annotation Processor,以Java代碼(或者編譯過的class)為輸入,生成.java文件作為輸出.這意味著我們可以生成新的Java代碼!這些生成的Java代碼是在生成的.java文件中,新生成的.java文件會(huì)和普通的手動(dòng)編寫的Java源代碼一樣被javac編譯
  3. 每一個(gè)注解處理器都是繼承于AbstractProcessor,需要關(guān)注的有以下4個(gè)方法
public abstract class AbstractProcessor implements Processor {

    //對一些工具進(jìn)行初始化
    public synchronized void init(ProcessingEnvironment processingEnv)
    
    //你在這里定義你的注解處理器注冊到哪些注解上,必須指定;
    //它的返回值是一個(gè)字符串的集合,包含本處理器想要處理的注解類型的合法全稱
    public Set<String> getSupportedAnnotationTypes()
    
    //指定該注解處理器使用的JAVA版本,通常返回SourceVersion.latestSupported()
    public SourceVersion getSupportedSourceVersion()
    
    //真正生成java代碼的地方
    //annotations:請求處理的注解類型集合
    //roundEnv:可以讓你查詢出包含特定注解的被注解元素约郁,相當(dāng)于“有關(guān)全局源碼的上下文環(huán)境”
    //如果返回 true缩挑,則這些注解已聲明并且不要求后續(xù) Processor 處理它們;
    //如果返回 false鬓梅,則這些注解未聲明并且可能要求后續(xù) Processor 處理它們
    public abstract boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv)
    
}
  1. 自定義注解處理器,就是繼承AbstractProcessor并重寫上述4個(gè)方法

關(guān)于編譯時(shí)Annotation解析,這里推薦一篇文章【Android】注解框架(三)-- 編譯時(shí)注解供置,手寫B(tài)utterKnife,按照文章上面流程敲一遍代碼,相信可以對自定義注解的創(chuàng)建及解析有一個(gè)深入的了解!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市绽快,隨后出現(xiàn)的幾起案子芥丧,更是在濱河造成了極大的恐慌悲关,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娄柳,死亡現(xiàn)場離奇詭異寓辱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)赤拒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門秫筏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挎挖,你說我怎么就攤上這事这敬。” “怎么了蕉朵?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵崔涂,是天一觀的道長。 經(jīng)常有香客問我始衅,道長冷蚂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任汛闸,我火速辦了婚禮蝙茶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诸老。我一直安慰自己隆夯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布别伏。 她就那樣靜靜地躺著蹄衷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厘肮。 梳的紋絲不亂的頭發(fā)上愧口,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機(jī)與錄音轴脐,去河邊找鬼调卑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛大咱,可吹牛的內(nèi)容都是我干的恬涧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼碴巾,長吁一口氣:“原來是場噩夢啊……” “哼溯捆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤提揍,失蹤者是張志新(化名)和其女友劉穎啤月,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劳跃,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谎仲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刨仑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郑诺。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖杉武,靈堂內(nèi)的尸體忽然破棺而出辙诞,到底是詐尸還是另有隱情,我是刑警寧澤轻抱,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布飞涂,位于F島的核電站,受9級特大地震影響祈搜,放射性物質(zhì)發(fā)生泄漏较店。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一夭问、第九天 我趴在偏房一處隱蔽的房頂上張望泽西。 院中可真熱鬧曹铃,春花似錦缰趋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至评甜,卻和暖如春灰粮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忍坷。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工粘舟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人佩研。 一個(gè)月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓柑肴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親旬薯。 傳聞我的和親對象是個(gè)殘疾皇子晰骑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容