• <menu id="gyiem"><menu id="gyiem"></menu></menu>
  • <menu id="gyiem"><code id="gyiem"></code></menu>

    Java進階(一)Annotation(注解)

    原創文章,轉載請務必將下面這段話置于文章開頭處(保留超鏈接)。
    本文轉發自技術世界原文鏈接 http://www.luozeyang.com/2016/01/17/Java1_注解Annotation

    概念

    Annotation是Java5開始引入的特性。它提供了一種安全的類似于注釋和Java doc的機制。實事上,Annotation已經被廣泛用于各種Java框架,如Spring,Jersey,JUnit,TestNG。注解相當于是一種嵌入在程序中的元數據,可以使用注解解析工具或編譯器對其進行解析,也可以指定注解在編譯期或運行期有效。這些元數據與程序業務邏輯無關,并且是供指定的工具或框架使用的。

    Meta Annotation

    元注解的作用就是負責注解其他注解。Java5定義了4個標準的Meta Annotation類型,它們被用來提供對其它 Annotation類型作說明。

    @Target

    @Target說明了Annotation所修飾的對象范圍:Annotation可被用于 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了@Target可更加明晰其修飾的目標。

    @Target作用:用于描述注解的使用范圍,即被描述的注解可以用在什么地方

    @Target取值(ElementType)

    • CONSTRUCTOR:用于描述構造器
    • FIELD:用于描述域
    • LOCAL_VARIABLE:用于描述局部變量
    • METHOD:用于描述方法
    • PACKAGE:用于描述包
    • PARAMETER:用于描述參數
    • TYPE:用于描述類、接口(包括注解類型) 或enum聲明

    @Retention

    @Retention定義了該Annotation的生命周期:某些Annotation僅出現在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另一些在class被裝載時將被讀取(請注意并不影響class的執行,因為Annotation與class在使用上是被分離的)。@Retention有唯一的value作為成員。

    @Retention作用:表示需要在什么級別保存該注釋信息,用于描述注解的生命周期(即:被描述的注解在什么范圍內有效)

    @Retention取值來自java.lang.annotation.RetentionPolicy的枚舉類型值

    • SOURCE:在源文件中有效(即源文件保留)
    • CLASS:在class文件中有效(即class保留)
    • RUNTIME:在運行時有效(即運行時保留)

    @Documented

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

    @Inherited

    @Inherited 是一個標記注解。如果一個使用了@Inherited修飾的annotation類型被用于一個class,則這個Annotation將被用于該class的子類。

    自定義Annotation

    在實際項目中,經常會碰到下面這種場景,一個接口的實現類或者抽象類的子類很多,經常需要根據不同情況(比如根據配置文件)實例化并使用不同的子類。典型的例子是結合工廠使用職責鏈模式。

    此時,可以為每個實現類加上特定的Annotation,并在Annotation中給該類取一個標識符,應用程序可通過該標識符來判斷應該實例化哪個子類。

    下面這個例子,定義了一個名為Component的Annotation,它包含一個名為identifier的成員變量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.jasongj.annotation;

    import java.lang.annotation.Documented;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface Component {
    String identifier () default "";
    }

    對于上文所說的實現類加上@Component

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package com.jasongj;

    import com.jasongj.annotation.Component;

    @Component(identifier="upper")
    public class UpperCaseComponent {

    public String doWork(String input) {
    if(input != null) {
    return input.toUpperCase();
    } else {
    return null;
    }
    }
    }

    應用程序中可以通過反射獲取UpperCaseComponent對應的identifier

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.jasongj;

    import com.jasongj.annotation.Component;

    public class Client {
    public static void main(String[] args) {
    try {
    Class componentClass = Class.forName("com.jasongj.UpperCaseComponent");
    if(componentClass.isAnnotationPresent(Component.class)) {
    Component component = (Component)componentClass.getAnnotation(Component.class);
    String identifier = component.identifier();
    System.out.println(String.format("Identifier for "
    + "com.jasongj.UpperCaseComponent is ' %s '", identifier));
    } else {
    System.out.println("com.jasongj.UpperCaseComponent is not annotated by"
    + " com.jasongj.annotation.Component");
    }
    } catch (ClassNotFoundException ex) {
    ex.printStackTrace();
    }
    }
    }

    結果如下

    1
    Identifier for com.jasongj.UpperCaseComponent is ' upper '

    如果把@Component@Retention設置為 RetentionPolicy.SOURCE或者RetentionPolicy.CLASS,則會得到如下結果,驗證了上文中對@Retention的描述

    1
    com.jasongj.UpperCaseComponent is not annotated by com.jasongj.annotation.Component

    Java內置Annotation

    Annotation的語法比較簡單,除了@符號的使用外,他基本與Java固有的語法一致,JavaSE中內置三個標準Annotation,定義在java.lang中:

    1. @Override 是一個標記型Annotation,說明了被標注的方法覆蓋了父類的方法,起到了斷言的作用。如果給一個非覆蓋父類方法的方法添加該Annotation,編譯器將報編譯錯誤。它有兩個典型的使用場景,一是在試圖覆蓋父類方法卻寫錯了方法名時報錯,二是刪除已被子類覆蓋(且用Annotation修飾)的父類方法時報錯。
    2. @Deprecated 標記型Annotation,說明被修改的元素已被廢棄并不推薦使用,編譯器會在該元素上加一條橫線以作提示。該修飾具有一定的“傳遞性”:如果我們通過繼承的方式使用了這個棄用的元素,即使繼承后的元素(類,成員或者方法)并未被標記為@Deprecated,編譯器仍然會給出提示。
    3. @SuppressWarnnings 用于通知Java編譯器關閉對特定類、方法、成員變量、變量初始化的警告。此種警告一般代表了可能的程序錯誤,例如當我們使用一個generic collection類而未提供它的類型時,編譯器將提示“unchecked warning”的警告。通常當這種情況發生時,我們需要查找引起警告的代碼,如果它真的表示錯誤,我們就需要糾正它。然而,有時我們無法避免這種警告,例如,我們使用必須和非generic的舊代碼交互的generic collection類時,我們無法避免這個unchecked warning,此時可以在調用的方法前增加@SuppressWarnnings通知編譯器關閉對此方法的警告。

    @SuppressWarnnings不是標記型Annotation,它有一個類型為String[]的成員,這個成員的值為被禁止的警告名。常見的警告名為下。

    • unchecked 執行了未檢查的轉換時的警告。例如當使用集合時沒有用泛型來指定集合的類型
    • finally finally子句不能正常完成時的警告
    • fallthrough 當switch程序塊直接通往下一種情況而沒有break時的警告
    • deprecation 使用了棄用的類或者方法時的警告
    • seriel 在可序列化的類上缺少serialVersionUID時的警告
    • path 在類路徑、源文件路徑等中有不存在的路徑時的警告
    • all 對以上所有情況的警告

    Annotation與Interface的異同

    • Annotation類型使用關鍵字@interface而非interface。注意開頭的@符號
    • Annotataion的方法定義是受限制的。其方法必須聲明為無參數、無異常拋出的。這些方法同時也定義了Annotation的成員——方法名即為成員名,而方法返回類型即為成員類型。方法返回類型必須為Java基礎類型、Class類型、枚舉類型、Annotation類型或者相應的一維數組。方法后面可以使用default關鍵字和一個默認數值來聲明成員的默認值,null不能作為成員默認值。成員一般不能是泛型,只有當其類型是Class時可以使用泛型,因為此方法能夠用類型轉換將各種類型轉換為Class
    • Annotation和interface都可以定義常量、靜態成員類型。interface可以被實現或者繼承,Annotation不可以

    Java進階系列

    郭俊 Jason wechat
    歡迎關注作者微信公眾號【大數據架構】
    您的贊賞將支持作者繼續原創分享
    速赢彩app 泸州 | 资阳 | 阿拉尔 | 济南 | 仙桃 | 红河 | 四平 | 营口 | 东阳 | 崇左 | 三亚 | 乌海 | 沧州 | 赤峰 | 甘孜 | 汕尾 | 黄石 | 惠州 | 保定 | 余姚 | 永新 | 兴安盟 | 许昌 | 临猗 | 桐乡 | 丹阳 | 石狮 | 宿迁 | 晋中 | 黄冈 | 博尔塔拉 | 靖江 | 昆山 | 香港香港 | 盘锦 | 枣庄 | 黑河 | 普洱 | 广安 | 醴陵 | 德清 | 果洛 | 三亚 | 铜陵 | 海东 | 玉树 | 高雄 | 江苏苏州 | 玉树 | 吐鲁番 | 泰安 | 清徐 | 姜堰 | 湖南长沙 | 吉林长春 | 临沧 | 东莞 | 烟台 | 岳阳 | 昌吉 | 雄安新区 | 桂林 | 邯郸 | 辽宁沈阳 | 陕西西安 | 连云港 | 黔南 | 平顶山 | 大庆 | 安顺 | 象山 | 大兴安岭 | 营口 | 运城 | 姜堰 | 无锡 | 白山 | 东阳 | 和县 | 滨州 | 普洱 | 长兴 | 靖江 | 江西南昌 | 赤峰 | 泸州 | 萍乡 | 崇左 | 大连 | 哈密 | 咸宁 | 焦作 | 邢台 | 克拉玛依 | 台北 | 龙岩 | 三明 | 滁州 | 桐乡 | 宝鸡 | 三河 | 衢州 | 莒县 | 定安 | 阳江 | 普洱 | 中卫 | 舟山 | 江西南昌 | 宁德 | 义乌 | 邵阳 | 遵义 |