JAVA基礎(chǔ)之注解

1贱傀、注解的作用

Annotation(注解)是JDK 5.0引入的特性惨撇,它的基本作用就是修飾編程元素。

注解相當(dāng)于一種標(biāo)記府寒,在程序中加了注解就等于為程序打上了某種標(biāo)記魁衙。編譯器报腔、開發(fā)工具或其他程序可以用反射來了解該類,有什么樣的標(biāo)記剖淀,就去干相應(yīng)的事纯蛾。

注解的語法比較簡單,除了@符號的使用之外纵隔,與Java固有語法一致翻诉。JDK 5.0內(nèi)置了三種標(biāo)準(zhǔn)注解:

  • @Override:表示當(dāng)前的方法定義將覆蓋父類中的方法。
  • @Deprecated:表示當(dāng)前元素不推薦使用巨朦,是被棄用的代碼米丘。
  • @SuppressWarnings:忽略編譯器發(fā)出的警告信息。

注解有以下幾個(gè)作用:

  • 生成文檔糊啡。這是最常見的拄查,也是java 最早提供的注解。常用的有@see 棚蓄、@param 堕扶、@return
  • 跟蹤代碼依賴性,替代配置文件的功能梭依。比如Spring從 2.5版本 開始支持基于注解的配置∩运悖現(xiàn)在的框架基本都使用了注解來減少配置文件的數(shù)量。
  • 在編譯時(shí)進(jìn)行格式檢查役拴。如@override 放在方法前糊探,如果這個(gè)方法并不是覆蓋了父類方法,則編譯時(shí)就能檢查出來河闰。

2科平、元注解

Java 5.0提供了四種元注解——負(fù)責(zé)注解其他注解。

2.1 @Target

@Target說明了Annotation所修飾的對象范圍:Annotation可被用于 packages姜性、types(類瞪慧、接口、枚舉部念、Annotation類型)弃酌、類型成員(方法、構(gòu)造方法儡炼、成員變量妓湘、枚舉值)、方法參數(shù)和本地變量(如循環(huán)變量乌询、catch參數(shù))多柑。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標(biāo)。

作用:用于描述注解的使用范圍楣责,即該注解可以用在什么地方竣灌。

取值(ElementType枚舉類)有:

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

2.2 @Retention

@Retention定義了該注解被保留的時(shí)間長短:某些Annotation僅出現(xiàn)在源代碼中秆麸,而被編譯器丟棄初嘹;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機(jī)忽略沮趣,而另一些在class被裝載時(shí)將被讀韧头场(請注意并不影響class的執(zhí)行,因?yàn)锳nnotation與class在使用上是被分離的)房铭。使用@Retention可以限制注解的“生命周期”驻龟。

作用:用于描述注解的生命周期,即注解在什么范圍內(nèi)有效缸匪。

取值(RetentionPoicy枚舉類)有:

  • SOURCE:在源文件中有效
  • CLASS:在class文件中有效
  • RUNTIME:在運(yùn)行時(shí)有效

2.3 @Documented

@Documented是一種標(biāo)記性注解翁狐,被其標(biāo)記的注解會被包含在javadoc文檔中。

2.4 @Inherited

@Inherited 也是一種標(biāo)記性注解凌蔬,被其標(biāo)記的注解會允許子類繼承露懒。如果一個(gè)使用了@Inherited修飾的annotation類型被用于一個(gè)class,則該注解將被用于該class的子類砂心。

需要注意的是懈词,被@Inheriten標(biāo)記的注解只會被class的子類所繼承,類并不從它所實(shí)現(xiàn)的接口繼承annotation辩诞,方法也不從它所重載的方法繼承annotation坎弯。

如果我們使用java.lang.reflect去查詢一個(gè)@Inherited類型的annotation時(shí),反射代碼將檢查class和其父類译暂,直到發(fā)現(xiàn)指定的annotation類型被發(fā)現(xiàn)抠忘,或者到達(dá)類繼承結(jié)構(gòu)的頂層。

3秧秉、自定義注解

自定義注解的格式為:

public @interface 注解名 {定義體}

例如:

@Target(value = { ElementType.FIELD })
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface NotNull {
    
    int code() default -1;

    String message() default "";
}

@interface用來聲明一個(gè)注解褐桌,自動(dòng)繼承了java.lang.annotation.Annotation接口,在自定義注解時(shí)象迎,不能繼承其他的注解或接口荧嵌。

定義體中的每一個(gè)方法實(shí)際上是聲明了一個(gè)配置參數(shù),方法只能用public或默認(rèn)(default)兩種訪問權(quán)修飾砾淌,方法的名稱就是參數(shù)的名稱啦撮,返回值類型就是參數(shù)的類型(返回值類型只能是基本類型、Class汪厨、String赃春、enum)〗俾遥可以通過default來聲明參數(shù)的默認(rèn)值织中。

注解參數(shù)支持?jǐn)?shù)據(jù)類型:

所有基本數(shù)據(jù)類型(byte,int,short.long,double,float,boolean,char)

  • String類型
  • Class類型
  • Enum類型
  • Annotation類型
  • 以上所有類型的數(shù)組

注解元素必須有確定的值锥涕,要么在定義注解的默認(rèn)值中指定,要么在使用注解時(shí)指定狭吼,非基本類型的注解元素的值不可為null层坠。因此, 使用空字符串或0作為默認(rèn)值是一種常用的做法。這個(gè)約束使得處理器很難判斷一個(gè)元素是否缺失刁笙,因?yàn)槊總€(gè)注解的聲明中破花,所有元素都存在,并且都具有相應(yīng)的值疲吸,為了繞開這個(gè)約束座每,我們只能定義一些特殊的值,例如空字符串或者負(fù)數(shù)摘悴,一次表示某個(gè)元素不存在峭梳,在定義注解時(shí),這已經(jīng)成為一個(gè)習(xí)慣用法烦租。

如果成員名稱是value延赌,在賦值過程中可以簡寫;如果成員類型為數(shù)組叉橱,但是只賦值一個(gè)元素挫以,則也可以簡寫。上面的例子可以簡寫為:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotNull {
    
    int code() default -1;

    String message() default "";
}

上例自定義了名為@NotNull的注解窃祝,作用對象為field掐松,其目的是對類變量進(jìn)行非空檢驗(yàn)》嘈。可是大磺,到底怎么怎么利用它來進(jìn)行檢驗(yàn)?zāi)兀?/p>

使用注解最主要的部分在于對注解的處理,那么就會涉及到注解處理器探膊。從原理上講杠愧,注解處理器就是通過反射機(jī)制獲取被檢查字段上的注解信息,然后根據(jù)注解元素的值進(jìn)行特定的處理逞壁。

比如流济,在某網(wǎng)站注冊用戶,用戶輸入的信息會被封裝成一個(gè)User對象:

public class User {

    @NotNull(message = "用戶昵稱不能為空")
    private String userName;

    @NotNull(message = "密碼不能為空")
    private String password;

    private Integer age;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

要求用戶昵稱與密碼不能為空腌闯,因此userNamepassword字段被@NotNull注解绳瘟。

后臺程序接收到User對象后,可以通過反射機(jī)制探知哪些字段被@NotNull注解了姿骏,如果全部滿足要求再進(jìn)行下一步業(yè)務(wù)邏輯糖声;反之,返回錯(cuò)誤頁面。

public class UserTest {

    public static boolean testNotNull(User user) throws IllegalArgumentException, IllegalAccessException {
        Class<?> clazz = user.getClass(); // 獲取User的Class對象
        Field[] userFields = clazz.getDeclaredFields(); // 獲取User的所有Field對象
        for (Field field : userFields) {
            field.setAccessible(true); // User中的Field都是private的蘸泻,所以要先setAccessible
            NotNull notNullAnnotation = field.getAnnotation(NotNull.class); // 獲取Field的NotNull注解對象
            if (notNullAnnotation != null) { // 如果該Field被NotNull注解了琉苇,那么字段不能為空
                if (field.get(user) == null) {
                    System.out.println(notNullAnnotation.message());
                    return false;
                }
            }
        }

        return true;
    }

    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
        User user = new User();
        user.setUserName("chenlongfei");
        testNotNull(user);
    }
}

由于只填寫了昵稱而沒填密碼,不能通過驗(yàn)證蟋恬,控制臺打印出:

密碼不能為空

而該信息正是在@NotNull注解password字段時(shí)由message定義的翁潘。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市歼争,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渗勘,老刑警劉巖沐绒,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異旺坠,居然都是意外死亡乔遮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門取刃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹋肮,“玉大人,你說我怎么就攤上這事璧疗∨鞅纾” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵崩侠,是天一觀的道長漆魔。 經(jīng)常有香客問我,道長却音,這世上最難降的妖魔是什么改抡? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮系瓢,結(jié)果婚禮上阿纤,老公的妹妹穿的比我還像新娘。我一直安慰自己夷陋,他們只是感情好欠拾,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肌稻,像睡著了一般清蚀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上爹谭,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天枷邪,我揣著相機(jī)與錄音,去河邊找鬼。 笑死东揣,一個(gè)胖子當(dāng)著我的面吹牛践惑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嘶卧,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼尔觉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芥吟?” 一聲冷哼從身側(cè)響起侦铜,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钟鸵,沒想到半個(gè)月后钉稍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棺耍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年贡未,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒙袍。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俊卤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出害幅,到底是詐尸還是另有隱情消恍,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布矫限,位于F島的核電站哺哼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏叼风。R本人自食惡果不足惜取董,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望无宿。 院中可真熱鬧茵汰,春花似錦、人聲如沸孽鸡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彬碱。三九已至豆胸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間巷疼,已是汗流浹背晚胡。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人估盘。 一個(gè)月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓瓷患,卻偏偏與公主長得像,于是被迫代替她去往敵國和親遣妥。 傳聞我的和親對象是個(gè)殘疾皇子擅编,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

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