官术网_书友最值得收藏!

1.1 注解

本節首先介紹注解的基本概念,理解什么是注解、注解的作用是什么。在此基礎上通過示例動手操作加深理解。

1.1.1 什么是注解

我們先看官方解釋:它提供了一種安全的類似注釋的機制,用來將任何的信息或元數據(metadata)與程序元素(類、方法、成員變量等)進行關聯。為程序的元素(類、方法、成員變量)加上更直觀、更明了的說明,這些說明信息與程序的業務邏輯無關,并且供指定的工具或框架使用。Annontation像一種修飾符一樣,應用于包、類型、構造方法、方法、成員變量、參數及本地變量的聲明語句中。Java注解是附加在代碼中的一些元信息,便于一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。注解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用,包含在java.lang.annotation包中。

看著上面的解釋是不是還是一頭霧水?其實我們可以更通俗地理解一下。最近幾年出現一個詞“斜杠青年”,還有黃某某拍攝的廣告語:給人貼標簽、下定義,總是很容易,而我卻不會因為一件事被定性。這里的斜杠青年、貼標簽都是把某些屬性附加給對象,和注解功能差不多,它提供了一種安全的類似注釋的機制,用來將任何信息或元數據(metadata)與程序元素(類、方法、成員變量等)進行關聯。我們可以再來理解一下這句話,這里的程序元素可以理解為人,信息或元數據理解為標簽,把標簽屬性(信息或元數據)賦給人(程序元素)。

上面兩段基本把什么注解解釋出來了,如果還是不知道注解是什么,那也沒關系。其實我們在編程中已經用到或者看到過了,比如@Override、@Deprecated。是不是很熟悉?其實它們就是注解。

1.1.2 內置注解

上面的@Override、@Deprecated都是Java中內置的注解,除了這兩個還有其他的內置注解。這里列舉了幾個常用的內置注解以及它們的作用。

● @Deprecated:編譯器在編譯階段遇到這個注解時會發出提醒警告,告訴開發者正在調用一個過時的元素,比如過時的方法、過時的類、過時的成員變量。

● @Override:提示子類要復寫父類中被@Override修飾的方法。

● @SuppressWarnings:阻止警告的意思。調用被@Deprecated注解的方法后,編譯器會警告提醒,而有時候開發者會忽略這種警告,他們可以在調用的地方通過@SuppressWarnings:達到目的。

● @SafeVarargs:參數安全類型注解。它的目的是提醒開發者不要用參數做一些不安全的操作,它的存在會阻止編譯器產生unchecked這樣的警告。它是在Java 1.7的版本中加入的。

● @FunctionalInterface:函數式接口注解,這個是Java 1.8版本引入的新特性。函數式編程很火,所以Java 8也及時添加了這個特性。函數式接口(Functional Interface)就是一個具有一個方法的普通接口。

1.1.3 元注解

通過前面的兩小節,我們應該對注解有了一定的認識,下面進一步地了解一下注解。我們在自定義注解時會出現圖1-1所示的一些選項。

圖1-1

這些選項@Retention、@Target、@Documented其實就是元注解。在創建時配置這些元注解,我們也可以推斷出元注解的作用是什么。元注解負責注解自定義注解。java.lang.annotation提供了5種元注解,專門注解其他的注解:

● @Retention:什么時候使用該注解。

● @Target:注解用于什么地方。

● @Documented:注解是否將包含在JavaDoc中。

● @Inherited:是否允許子類繼承該注解。

● @Repeatable:指定注解可重復使用。

1.@Retention定義注解的生命周期

● RetentionPolicy.SOURCE:在編譯階段丟棄。這些注解在編譯結束之后不再有任何意義,所以它們不會寫入字節碼。@Override和@SuppressWarnings都屬于這類注解。

● RetentionPolicy.CLASS:在類加載的時候丟棄。在字節碼文件的處理中有用。注解默認使用這種方式。

● RetentionPolicy.RUNTIME:始終不會丟棄,運行期也保留該注解,因此可以使用反射機制讀取該注解的信息。我們自定義的注解通常使用這種方式。

2.@Target表示注解用于什么地方

默認值為任何元素,表示該注解用于什么地方??捎玫腅lementType參數包括:

● ElementType.CONSTRUCTOR:用于描述構造器。

● ElementType.FIELD:成員變量、對象、屬性(包括enum實例)。

● ElementType.LOCAL_VARIABLE:用于描述局部變量。

● ElementType.METHOD:用于描述方法。

● ElementType.PACKAGE:用于描述包。

● ElementType.PARAMETER:用于描述參數。

● ElementType.TYPE:用于描述類、接口(包括注解類型)或enum聲明。

3.@Documented是一個簡單的Annotations標記注解

表示是否將注解信息添加在Java文檔中。

4.@Inherited定義注解和子類的關系

@Inherited元注解是一個標記注解,闡述了某個被標注的類型是被繼承的。如果一個使用了@Inherited修飾的annotation類型被用于一個class,那么這個annotation將被用于該class的子類。

5.@Repeatable指定注解可重復使用

使用@Repeatable修飾表示該注解可以為重復使用。

1.1.4 自定義注解

元注解是負責注解自定義注解的。自定義注解時是有一些規則限制的,具體如下:

● Annotation型定義為@interface,所有的Annotation會自動繼承java.lang.Annotation這一接口,并且不能再去繼承別的類或是接口。

● 參數成員只能用public或默認(default)這兩個訪問權修飾。

● 參數成員只能用基本類型byte、short、char、int、long、float、double、boolean八種基本數據類型和String、Enum、Class、annotations等數據類型,以及這一些類型的數組。

● 要獲取類方法和字段的注解信息,必須通過Java的反射技術來獲取Annotation對象,因為除此之外沒有其他獲取注解對象的方法。

● 注解也可以沒有定義成員。

我們這里自定義一個注解來練習一下,主要用來演示自定義注解以及注解的繼承。

1.定義CustomDescription注解

CustomDescription注解相當于標簽。為了能多貼標簽,又定義了注解容器CustomDescriptions。其中,@Retention(RUNTIME)表示在運行時環境也可以獲取注解,@Inherited表示可繼承,@Repeatable(CustomDescriptions.class)表示該注解可多次使用。

 package CusAnnontation;
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import java.lang.annotation.Documented;
 import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 import java.lang.annotation.Repeatable;
     @Documented
     @Retention(RUNTIME)
     @Target(TYPE)
     @Inherited
     @Repeatable(CustomDescriptions.class)
 public @interface CustomDescription {
     String description() default "";
     }

CustomDescriptions容器:

 package CusAnnontation;
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import java.lang.annotation.Documented;
 import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
     @Documented
     @Retention(RUNTIME)
     @Target(TYPE)
     @Inherited
 public @interface CustomDescriptions {
     CustomDescription[] value();
     }

2.實現繼承關系

這里為了演示,我們創建了兩個類:一個基類Person,一個子類Student。在Person類加兩個自定義注解,在Student中加一個自定義注解。

Person

Student

3.通過反射獲取注解屬性值

這里我們想通過反射(可以先不要理解)獲取Student類的注解值,那么問題來了,它是輸出什么的呢?會輸出“description:學生”嗎?并不是,而是輸出父類Person的注解。

輸出:

     description:基類
     description:人

如果想輸出子類Student的注解該怎么設置呢?很簡單,只需在子類Student上覆蓋父類的注解就好。

     @CustomDescription(description="學生")
     @CustomDescription(description="人")
 public class Student extends Person

輸出:

     description:學生
     description:人

此時輸出的就是子類的注解值了。這里我們還可以驗證@Retention生命周期的作用,只需要把@Retention(RUNTIME)改成CLASS,再運行就會報錯,因為main方法中的custormDescriptions對象是一個null空值。不過自定義注解一般來說都是使用@Retention(RUNTIME)。

1.1.5 注解使用場景介紹

在上一小節通過實例學習了自定義注解的使用,之后就該解決怎么用的問題了。其實,注解應用的場景還是挺多的。

(1)使用注解做bean的屬性值校驗,例如在開發Java服務器端代碼時,會要求對外部傳來的參數合法性進行驗證。hibernate-validator提供了一些常用的參數校驗注解。

(2)使用注解做權限控制。例如,shiro框架中有5個權限注解,我們也可以自定義注解進行權限控制。

(3)代替配置文件功能,像Spring基于注解的配置,減少了xml的配置。

(4)可以生成文檔,像Java代碼注釋中的@see、@param等。

這里只是列舉了幾個使用場景,其實還有很多地方可以使用注解。

主站蜘蛛池模板: 体育| 彩票| 三门峡市| 塔城市| 乌拉特前旗| 嘉兴市| 全椒县| 康马县| 辛集市| 霍山县| 乌拉特后旗| 满洲里市| 乌审旗| 仁布县| 武平县| 临澧县| 湘乡市| 贺州市| 涪陵区| 新密市| 华安县| 宁海县| 宁蒗| 会东县| 铜鼓县| 山西省| 陆河县| 太原市| 千阳县| 汤阴县| 贞丰县| 西贡区| 五河县| 雅江县| 宜兰市| 民权县| 关岭| 静海县| 西青区| 绥化市| 榆社县|