文章目錄
- 前言
- 一、認識注解
- 1.1、介紹注解
- 1.2、開發中常見注解使用
- 二、自定義注解
- 2.1、自定義注解說明
- 2.2、JDK1.5提供的四個元注解
- 三、利用反射擷取注解資訊
- 四、JDK8中注解的新特性
- 4.1、可重複注解(兩種方式)
- 兩種方式實作
- 擷取可重複注解的值(兩種方式)
- 4.2、新增類型注解(2個)
- 參考文章
前言
本篇文章是對之前學習java基礎知識的再整理,通過看視訊以及查閱部落格進行彙總整理。部分圖引用的是尚矽谷的教案,覺得比較好,若有侵權,請聯系我删除。
部落格文章彙總:部落格目錄索引(持續更新)
一、認識注解
1.1、介紹注解
注解
(Annotation):從
JDK5.0
開始,Java增加了對中繼資料(MetaData)的支援,及注解。
Annotation
就是代碼中的特殊标記,這些标記可以通過設定在編譯時、類加載時、運作時讀取來執行相應的處理。通過注解可以在不改變原有邏輯的情況下,在源檔案中嵌入一些補充資訊。并且代碼分析工具、開發工具和部署工具都可以通過這些補充資訊進行驗證部署。
-
可以像修飾符一樣使用,可用于修飾包、類、構造器、方法…之前,并且能夠設定指定的值儲存在Annoation中的屬性裡,例如name=value。Annoation
目的:在JavaSE中,注解的使用目的例如标記過時的功能(
@Deprecated
), 忽略警告(
@SuppressWarnings
;在JavaEE/Android開發中注解占據了更重要的角色,例如
Spring
架構中的
AOP
通過注解來配置任意方法的切面,使用注解來代替JavaEE舊版中的繁冗代碼與XML配置。
- 未來的開發模式都是基于注解的,例如:
以上都是基于注解,Spring2.5
,JPA
,Hibernate3.X
。Struts2
-
架構=注解+反射+設計模式
1.2、開發中常見注解使用
使用注解前需要在前面加上
@
符号,可以将其當做一個修飾符來使用。
1、用于生成文檔的相關注解
一般使用于注釋中,用于在使用
javadoc
工具來生成文檔
- 類注釋中:
-
:标明開發該類子產品的作者,多個作者之間可使用@author
分割。,
-
:标明該類子產品的版本。@version
-
:從哪個版本開始增加的,我們常看到源代碼注釋中會标注。@since
-
:參考轉向,也就是相關主題。@see
- 一般用于方法中:
-
:用于在方法注釋中,對方法中某參數的說明,如果沒有參數就不能寫。@param
-
:用于在方法注釋中,對方法傳回值的說明,如果方法的傳回值類型是void就不能寫。@return
-
:對方法可能抛出的異常進行說明 ,如果方法沒有用throws顯式抛出的異常就不能寫 其中@exception
2、在編譯時進行格式檢查(JDK内置的三個基本注解)
一般修飾在方法:
-
: 限定重寫父類方法,該注解隻能用于方法,可以來檢查是否為重寫的方法。@Override
-
: 用于表示所修飾的元素(類, 方法等)已過時。通常是因為所修飾的結構危險或存在更好的選擇。@Deprecated
-
: 抑制編譯器警告。@SuppressWarnings
3、跟蹤代碼依賴性,實作替代配置檔案功能
①Servlet3.0中提供的注解,使得不再需要在web.xml中進行Servlet的部署通路。

- 通過使用
來代替掉下面的配置檔案(減少xml配置)。@WebServlet("/login")
②
Spring
中事務的配置,隻用一個注解來替換掉了配置檔案
二、自定義注解
2.1、自定義注解說明
對于自定義注解的說明:
- 定義
時需要使用Annotation
關鍵字。@interface
- 自定義注解自動繼承了
接口,包含四個方法java.lang.annotation.Annotation
、equals()
、hashCode()
、toString()
。annotationType()
-
中的成員變量以無參數方法的形式來聲明。Annoation
- 其方法名和傳回值定義了該成員的名字和類型,稱之為配置參數。其類型隻能是
、8種基本資料類型
、String類型
、Class類型
、enum類型
以及Annotation類型
。上面所有類型的數組
- 可以在定義成員變量時指定參數值,可在成員變量後使用
來進行初始化。default 預設值
- 若是
中隻有一個參數成員,建議使用參數名為Annoation
。value
使用說明:若是使用的注解中含有配置參數(即成員變量),那麼使用時需要在()中指定參數值(對于有預設值的可以不寫因為會自動指派),例如:
@注解(參數=值)
;若是
Annotation
中隻有一個成員那麼我們在使用時可以省略
參數=
,
例如:@注解(值)
。
注意:沒有成員定義的Annotation稱為
标記
;包含成員變量的Annotation稱為
中繼資料
。
自定義注解
public @interface MyAnnotation {
String value() default "changlu";
}
@MyAnnotation(value = "changlu") //或 @MyAnnotation("liner") 或 @MyAnnotation()
class Person{
}
-
與@MyAnnotation(value = "changlu")
都相當于對其中的value重新指派了,由于注解中隻有一個成員是以可以省略參數直接填值。@MyAnnotation("liner")
-
:會預設使用注解成員中的值。@MyAnnotation()
2.2、JDK1.5提供的四個元注解
四個标準的元注解:
Retention
、
Target
、
Documented
、
Inherited
@Retention
@Retention
:用來指定該Annotation的生命周期。
@Documented
@Retention(RetentionPolicy.RUNTIME) //生命周期為運作時
@Target(ElementType.ANNOTATION_TYPE) //隻可标注在注解類型上
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
//@Retention的成員傳回值RetentionPolicy,一個枚舉類
public enum RetentionPolicy {
SOURCE,//在源檔案中有效(僅在源檔案中保留),編譯器編譯時會忽略該注解
CLASS,//僅在class檔案中有效(即class保留),當運作Java程式時,JVM不會保留注解。
RUNTIME//:在運作時有效(即運作時保留),當運作 Java 程式時, JVM 會保留注釋。程式可以通過反射擷取該注釋。
}
- 該注解使用不同
的枚舉執行個體表示的不同生命周期RetentionPolicy
@Target
@Target
:用于指定被修飾的Annotation能用于修飾哪些程式元素(如方法、類、包、參數…)。
@Documented
@Retention(RetentionPolicy.RUNTIME) //生命周期為運作時
@Target(ElementType.ANNOTATION_TYPE)//隻可标注在注解類型上
public @interface Target {
//是一個數組枚舉類
ElementType[] value();
}
//@Target的成員傳回值是一個注解
public enum ElementType {
TYPE,//使用于描述類、接口(包括注解類型)或enum聲明
FIELD,//使用于屬性(包含注解内容)
METHOD,//使用于方法
PARAMETER,//參數
CONSTRUCTOR,//用于描述構造器
LOCAL_VARIABLE,//描述局部變量
ANNOTATION_TYPE,//描述注解類型聲明
PACKAGE,//包
TYPE_PARAMETER,//jdk1.8新增,表示該注解能寫在類型變量的聲明語句中(如:泛型聲明)
TYPE_USE//jdk1.8新增,表示該注解能寫在使用類型的任何語句中
}
-
:即可在任何語句中添加注解。@Tatget({ElementType.TYPE_USE})
@Documented
@Documented
: 用于指定被 修飾的 Annotation 類能夠被 javadoc工具提取成文檔。預設情況下,javadoc是不包括注解的。
- 若定義了
的注解務必設定@Documented
的值為@Retention
(生命周期為運作時)。Runtime
@Documented
@Retention(RetentionPolicy.RUNTIME) //生命周期是運作時
@Target(ElementType.ANNOTATION_TYPE) //隻可标注在注解類型上
public @interface Documented {
}
@Inherited
@Inherited
:被其修飾的注解具有繼承性,若某個類使用了被@Inherited修飾的注解,則其子類将自動具有該注解。
- 實際使用較少。
@Documented
@Retention(RetentionPolicy.RUNTIME)//生命周期是運作時
@Target(ElementType.ANNOTATION_TYPE)//隻可标注在注解類型上
public @interface Inherited {
}
三、利用反射擷取注解資訊
自定義注解:
@Documented
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//運作時
@Inherited
public @interface MyAnnotation {
String value() default "changlu";
}
通過反射擷取到類的注解以及注解值:
@MyAnnotation("clle")
class Person{
}
class Student extends Person{
}
public class Test {
public static void main(String[] args) {
Class<Person> clazz = Person.class;
//擷取該類上指定的注解類型
MyAnnotation anno = clazz.getAnnotation(MyAnnotation.class);
System.out.println(anno.value());//clle
//檢視Student是否繼承了Person的注解
Annotation[] annotations = Student.class.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);//@xyz.changlu.MyAnnotation(value=clle)
}
}
}
認識一下 AnnotatedElement
接口
Class實作了該接口,才會有擷取注解的相關方法:
-
:此元素上是否存在指定注解類型,若存在傳回true,不存在傳回false。isAnnotationPresent()
-
:擷取該元素上指定注解類型的執行個體。getAnnotation()
-
:擷取該元素上的所有注解執行個體。getAnnotations()
-
:擷取該元素上指定注解類的所有執行個體。getAnnotationsByType
Class
類的繼承圖:
四、JDK8中注解的新特性
4.1、可重複注解(兩種方式)
兩種方式實作
什麼是可重複注解呢?就是在同一個部分上定義兩個或多個相同的注解,其中的值可不一樣。
①jdk1.8之前,需要通過再定義一個注解,其中包含我們想要使用的注解數組
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//運作時
@Inherited
public @interface MyAnnotation {
String value() default "changlu";
}
//該注解中我們定義@MyAnnotation數組
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//運作時
@Inherited
@interface MyAnnotations{
//定義注解數組
MyAnnotation[] value();
}
@MyAnnotations({@MyAnnotation("changlu"),@MyAnnotation("liner")})
class Person{
}
- 我們通過定義
注解的成員為注解數組形式來實作可重複注解。@MyAnnotations
②jdk1.8新增 @Repeatable
注解
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Repeatable(MyAnnotations.class)//注意:這裡新增使用@Repeatable()其中值為一個Class類就是下面定義的MyAnnotations
public @interface MyAnnotation {
String value() default "changlu";
}
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//運作時
@Inherited
@interface MyAnnotations{
//定義注解數組
MyAnnotation[] value();
}
- 在
中使用了@MyAnnotation
注解,其中定義了指定一個容器注解。@Repeatable(MyAnnotations.class)
@MyAnnotation("changlu")
@MyAnnotation("liner")
class Person{
}
這樣我們就能夠直接在一個類上定義多個相同注解了,相較于第一種方式需要先聲明
@MyAnnotations
,其中再包裹兩個注解。
我們再看一下
@Repeatable
注解:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
Class<? extends Annotation> value();//其中成員的傳回值為一個Class類型
}
擷取可重複注解的值(兩種方式)
擷取上面使用
@Repeatable
注解方法的設定的重複注解:
@MyAnnotation("changlu")
@MyAnnotation("liner")
class Person{
}
public class AnnotationTest {
public static void main(String[] args) {
//方式一:通過getAnnotation()擷取MyAnnotations容器注解的執行個體,接着周遊
MyAnnotations annotation = Person.class.getAnnotation(MyAnnotations.class);
MyAnnotation[] value = annotation.value();
for (MyAnnotation myAnnotation : value) {
System.out.println(myAnnotation.value());
}
//changlu
//liner
}
//方式二:通過使用getAnnotationsByType()擷取MyAnnotation注解數組,接着重複周遊即可
@Test
public void test(){
MyAnnotation[] annos = Person.class.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation anno : annos) {
System.out.println(anno.value());
}
//changlu
//liner
}
}
- 通過查閱部落格得知使用新增的
,在編譯器編譯時實際上也是轉換為使用的@Repeatable
注解表示。MyAnnotations
@MyAnnotation("changlu")
@MyAnnotation("liner")
轉換後
@MyAnnotations(value=[@MyAnnotation("changlu"),@MyAnnotation("liner")])
//并且在位元組碼中數組使用[]來表示
對于擷取單個注解值使用
getAnnotation()
方法,擷取重複注解使用
getAnnotationsByType()
。
詳細内容可看我下面的參考文章[1]。
4.2、新增類型注解(2個)
也就是在
@Target
注解中的成員參數
ElementType
枚舉類中添加了兩個執行個體:
-
:表示該注解能寫在類型變量的聲明語 句中(如:泛型聲明)。ElementType.TYPE_PARAMETER
-
:表示該注解能寫在使用類型的任何語句中。ElementType.TYPE_USE
差別說明:在
Java 8
之前,注解隻能是在聲明的地方所使用,
Java8
開始,注解可以應用在任何地方(可直接使用
ElementType.TYPE_USE
)。
參考文章
[1]. Java 8 可重複注解的了解與應用
我是長路,感謝你的閱讀,如有問題請指出,我會聽取建議并進行修正。
歡迎關注我的公衆号:長路Java,其中會包含軟體安裝等其他一些資料,包含一些視訊教程以及學習路徑分享。
學習讨論qq群:891507813 我們可以一起探讨學習
注明:轉載可,需要附帶上文章連結