注解Annotation

注解Annotation

概念相關(guān)

JDK5開始,java增加了對元數(shù)據(jù)(MetaData)的支持砸王,也就是Annotation赤赊。

Annotation其實就是代碼里的特殊標(biāo)記,這些編輯可以在編譯洽沟、類加載囤锉、運行的時候被讀取坦弟,并執(zhí)行相應(yīng)的處理」俚兀可以實現(xiàn)不改變原有邏輯的情況下酿傍,源代碼中嵌入補充信息。

它是一種程序元素(類区丑、方法、成員變量等)的元數(shù)據(jù),不會影響程序邏輯沧侥。

注解分類

根據(jù)注解參數(shù)的個數(shù)分類

  1. 標(biāo)記注解:一個沒有成員定的以的Annotation可霎;這種Annotation類型僅適用自身的存在與否來為我們提供信息。
  2. 單值注解:只存在 value = "xxx"宴杀;通常@Annotation("xxx");value=可以省略
  3. 完整注解

根據(jù)注解適用方法和用途分類

  1. JDK內(nèi)置系統(tǒng)注解
  2. 元注解:標(biāo)記其它注解的注解
  3. 自定義注解

JDK常用的注解

  • @Override : 重寫方法

  • @Deprecated : 表示某個程序元素(類癣朗、方法等)已經(jīng)過時

  • @SuppressWarnings : 抑制編譯器警告

  • @SafeVarargs : 堆污染警告(java7出現(xiàn))

    堆污染:把一個不帶泛型的對象賦給一個帶泛型的變量

    List list = new ArrayList<Integer>();
    list.add(20);
    List<String> ls = list;
    System.out.println(ls.get(0));
    
  • @Functionallnterface : 函數(shù)式接口

    接口中只有一個抽象方法,該接口就是函數(shù)式接口旺罢,@FunctionalInterface 就是用來執(zhí)行某個接口必須是函數(shù)式接口旷余。

JDK元Annotation

5個元Annotation 用于修飾其它Annotation的定義

  • @Retention : 用于執(zhí)行被修飾的Annotation可以保留多長時間

    value的值:

    ? RetentionPolicy.CLASS : 編譯器把Annotation記錄在class中,當(dāng)運行java程序時扁达,jvm獲取不到正卧,默認(rèn)值

    ? RetentionPolicy.RUNTIME:編譯器把Annotation記錄在class中,當(dāng)運行java程序時跪解,jvm可以獲取到Annotation信息炉旷,程序可以通過反射獲取Annotation信息

    ? RetentionPolicy.SOURCE:編譯器把Annotation記錄在源碼中,class中丟失該Annotation

    @Retention(value=RetentionPolicy.RUNTIME)
    public @interface Test{}
    

    說明:如果使用注解只為value成員變量指定值時叉讥,可以括號內(nèi)直接指定value,如:

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Test{}
    
  • @Target

    @Target 只能修飾一個Annotation窘行,用于指定被修飾的Annotation能用于修飾在什么地方

    value 說明
    ElementType.ANNOTATION_TYPE 只能修飾Annotation
    ElementType.CONSTRUCTOR 構(gòu)造器
    ElementType.FIELD 成員變量
    ElementType.LOCAL_VARIABLE 局部變量
    ElementType.METHOD 方法
    ElementType.PACKAGE
    ElementType.PARAMETER 參數(shù)
    ElementType.TYPE 類、接口图仓、枚舉
  • @Documented

    用于指定被@Documented修飾的annotation修飾的類被javadoc工具提取成文檔

  • @Inherited

    用于指定被@Inherited修飾的annotation修飾的類罐盔,具有繼承性;如類A使用了@xxx (@xxx被@Inherited修飾)救崔,那么繼承類A的子類a會自動被@xxx修飾(無需顯示手動寫出)

自定義注解

格式:

public @interface AnnotationName { ... }

說明:

使用@interface自定義注解時惶看,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成的帚豪。在定義注解時候碳竟,不能繼承其它的注解或者接口。

注解支持的數(shù)據(jù)類型

  1. 基本類型(不支持包裝類型)
  2. String類型
  3. Class類型
  4. enum類型
  5. Annotation類型
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo {
    int value() default 0;
    String name() default "";
}

注解的運行原理

注解本質(zhì)是一個繼承了Annotation的特殊接口狸臣,其具體的實現(xiàn)類是java運行時生成的動態(tài)代理類(Debug是莹桅,可以看到動態(tài)代理對象$Proxy1,通過代理對象調(diào)用自定義注解(接口)的方法烛亦,會最終調(diào)用AnnotationInvocationHandlerinvoke方法诈泼。該方法會從memberValues 這個Map 中索引出對應(yīng)的值。而memberValues 的來源是Java 常量池)煤禽。通過反射獲取注解相關(guān)信息铐达。

注解處理類(AnnotatedElement;也叫注解處理器)檬果,獲取注解信息瓮孙。

Annotation接口唐断,代表注解的注解,是所有注解的父接口

AnnotatedElement接口杭抠,代表程序中可以接受注解的程序元素脸甘;該接口也叫注解處理器;如圖:

AnnotatedElement-UML.png
  • <T extends Annotation> T getAnnotation(Class<T> annotationClass)

    返回程序元素上存在的指定類型的注解偏灿,若不存在丹诀,則返回null

  • Annotation[] getAnnotations()

    返回該程序元素上存在的所有注解

  • boolean is AnnotationPresent(Class<?extends Annotation> annotationClass)

    判斷程序元素上是否包含指定類型的注解

  • Annotation[] getDeclaredAnnotations()

    返回直接存在于此元素上的所有注解(忽略繼承的注解)

獲取注解的過程;也就是上述五個繼承類中(注解處理器)翁垂,getAnnotations 的過程:

客戶端代碼:

Field name = client.getClass().getDeclaredField("name");
AnnotationDemo annotation = name.getAnnotation(AnnotationDemo.class);

Field.java

public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
    Objects.requireNonNull(annotationClass);
    return annotationClass.cast(declaredAnnotations().get(annotationClass));
}
private synchronized  Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
        if (declaredAnnotations == null) {
            Field root = this.root;
            if (root != null) {
                declaredAnnotations = root.declaredAnnotations();
            } else {
                declaredAnnotations = AnnotationParser.parseAnnotations(
                        annotations,
                        sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(getDeclaringClass()),
                        getDeclaringClass());
            }
        }
        return declaredAnnotations;

AnnotationParser.class

public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(byte[] var0, ConstantPool var1, Class<?> var2) {
        if (var0 == null) {
            return Collections.emptyMap();
        } else {
            try {
                return parseAnnotations2(var0, var1, var2, (Class[])null);
            } catch (BufferUnderflowException var4) {
                throw new AnnotationFormatError("Unexpected end of annotations.");
            } catch (IllegalArgumentException var5) {
                throw new AnnotationFormatError(var5);
            }
        }
    }
private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(byte[] var0, ConstantPool var1, Class<?> var2, Class<? extends Annotation>[] var3) {
        LinkedHashMap var4 = new LinkedHashMap();
        ByteBuffer var5 = ByteBuffer.wrap(var0);
        int var6 = var5.getShort() & '\uffff';

        for(int var7 = 0; var7 < var6; ++var7) {
            Annotation var8 = parseAnnotation2(var5, var1, var2, false, var3);
            if (var8 != null) {
                Class var9 = var8.annotationType();
                if (AnnotationType.getInstance(var9).retention() == RetentionPolicy.RUNTIME && var4.put(var9, var8) != null) {
                    throw new AnnotationFormatError("Duplicate annotation for class: " + var9 + ": " + var8);
                }
            }
        }

        return var4;
    }
 private static Annotation parseAnnotation2(ByteBuffer var0, ConstantPool var1, Class<?> var2, boolean var3, Class<? extends Annotation>[] var4) {
        int var5 = var0.getShort() & '\uffff';
        Class var6 = null;
        String var7 = "[unknown]";

        try {
            try {
                var7 = var1.getUTF8At(var5);
                var6 = parseSig(var7, var2);
            } catch (IllegalArgumentException var18) {
                var6 = var1.getClassAt(var5);
            }
        } catch (NoClassDefFoundError var19) {
            if (var3) {
                throw new TypeNotPresentException(var7, var19);
            }

            skipAnnotation(var0, false);
            return null;
        } catch (TypeNotPresentException var20) {
            if (var3) {
                throw var20;
            }

            skipAnnotation(var0, false);
            return null;
        }

        if (var4 != null && !contains(var4, var6)) {
            skipAnnotation(var0, false);
            return null;
        } else {
            AnnotationType var8 = null;

            try {
                var8 = AnnotationType.getInstance(var6);
            } catch (IllegalArgumentException var17) {
                skipAnnotation(var0, false);
                return null;
            }

            Map var9 = var8.memberTypes();
            LinkedHashMap var10 = new LinkedHashMap(var8.memberDefaults());
            int var11 = var0.getShort() & '\uffff';

            for(int var12 = 0; var12 < var11; ++var12) {
                int var13 = var0.getShort() & '\uffff';
                String var14 = var1.getUTF8At(var13);
                Class var15 = (Class)var9.get(var14);
                if (var15 == null) {
                    skipMemberValue(var0);
                } else {
                    Object var16 = parseMemberValue(var15, var0, var1, var2);
                    if (var16 instanceof AnnotationTypeMismatchExceptionProxy) {
                        ((AnnotationTypeMismatchExceptionProxy)var16).setMember((Method)var8.members().get(var14));
                    }

                    var10.put(var14, var16);
                }
            }

            return annotationForMap(var6, var10);
        }
    }
public static Annotation annotationForMap(final Class<? extends Annotation> var0, final Map<String, Object> var1) {
        return (Annotation)AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
            public Annotation run() {
                //該句是重點铆遭;返回動態(tài)代理對象
                return (Annotation)Proxy.newProxyInstance(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1));
            }
        });
    }
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    private static final long serialVersionUID = 6182022883658399397L;
    private final Class<? extends Annotation> type;
    //該句是重點:對象池
    private final Map<String, Object> memberValues;
    private transient volatile Method[] memberMethods = null;

    AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
        Class[] var3 = var1.getInterfaces();
        if (var1.isAnnotation() && var3.length == 1 && var3[0] == Annotation.class) {
            this.type = var1;
            this.memberValues = var2;
        } else {
            throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
        }
    }

    public Object invoke(Object var1, Method var2, Object[] var3) {
      
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市沿猜,隨后出現(xiàn)的幾起案子枚荣,更是在濱河造成了極大的恐慌,老刑警劉巖邢疙,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棍弄,死亡現(xiàn)場離奇詭異,居然都是意外死亡疟游,警方通過查閱死者的電腦和手機呼畸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颁虐,“玉大人蛮原,你說我怎么就攤上這事×砑ǎ” “怎么了儒陨?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長笋籽。 經(jīng)常有香客問我蹦漠,道長,這世上最難降的妖魔是什么车海? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任笛园,我火速辦了婚禮,結(jié)果婚禮上侍芝,老公的妹妹穿的比我還像新娘研铆。我一直安慰自己,他們只是感情好州叠,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布棵红。 她就那樣靜靜地躺著,像睡著了一般咧栗。 火紅的嫁衣襯著肌膚如雪逆甜。 梳的紋絲不亂的頭發(fā)上虱肄,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音交煞,去河邊找鬼浩峡。 笑死,一個胖子當(dāng)著我的面吹牛错敢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缕粹,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼稚茅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了平斩?” 一聲冷哼從身側(cè)響起亚享,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绘面,沒想到半個月后欺税,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡揭璃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年晚凿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘦馍。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡歼秽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出情组,到底是詐尸還是另有隱情燥筷,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布院崇,位于F島的核電站肆氓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏底瓣。R本人自食惡果不足惜谢揪,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望濒持。 院中可真熱鬧键耕,春花似錦、人聲如沸柑营。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽官套。三九已至酒奶,卻和暖如春蚁孔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惋嚎。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工杠氢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人另伍。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓鼻百,卻偏偏與公主長得像,于是被迫代替她去往敵國和親摆尝。 傳聞我的和親對象是個殘疾皇子温艇,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

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

  • 是高考完的那段日子勺爱,我很久很久不能找尋到奮斗的意義。 我落了榜讯检。這是意料之中的事琐鲁,因為我不曾盡力過。 我不能再自由...
    原來你還在地獄閱讀 226評論 0 0
  • 天色漸暗人灼,你究竟在想什么围段。 說了人生如戲,誰也不知道下一秒會發(fā)生什么投放。 可是誰都不聽蒜撮。 人生喧嘩,誰會停下來看看沿...
    洛橘生閱讀 139評論 0 1
  • 樊榮強 最近些年經(jīng)濟發(fā)展了,社會進步了耗绿,開心的事情就多了苹支。開心的事情一多,經(jīng)常就會搞慶典误阻,搞慶典就有人難免會要講話...
    樊榮強閱讀 575評論 2 3
  • 最近在追老胡演的《獵場》债蜜,今天賈衣玫給鄭秋冬說了要換工作單位的事,只換工作究反,別的都不變寻定。老胡的一句會嗎?精耐?問得...
    聽雨閣xiaoyu閱讀 222評論 0 2
  • 我問佛∶為何不給所有女子美麗的容顏卦停? 佛曰∶那只是曇花一現(xiàn)向胡,用來蒙蔽世俗的眼恼蓬,沒有什麼美可以抵過一顆純凈仁愛的心,...
    一舨閱讀 2,564評論 4 7