Java注解總結(jié)
注解(Annotation)在JDK1.5之后增加的一個新特性被啼,注解的引入意義很大,有很多非常有名的框架棠枉,比如Hibernate浓体、Spring等框架中都大量使用注解。注解作為程序的元數(shù)據(jù)嵌入到程序辈讶。注解可以被解析工具或編譯工具解析命浴。
注解屬于 Java中的一種類型,同 類class 和 接口interface 一樣荞估。
一咳促、元數(shù)據(jù)
要想理解注解(Annotation)的作用,就要先理解Java中元數(shù)據(jù)的概念勘伺。
1. 元數(shù)據(jù)概念
元數(shù)據(jù)是關(guān)于數(shù)據(jù)的數(shù)據(jù)跪腹。在編程語言上下文中,元數(shù)據(jù)是添加到程序元素如方法飞醉、字段冲茸、類和包上的額外信息。對數(shù)據(jù)進行說明描述的數(shù)據(jù)缅帘。
2.元數(shù)據(jù)的作用
一般來說轴术,元數(shù)據(jù)可以用于創(chuàng)建文檔(根據(jù)程序元素上的注釋創(chuàng)建文檔),跟蹤代碼中的依賴性(可聲明方法是重載钦无,依賴父類的方法)逗栽,執(zhí)行編譯時檢查(可聲明是否編譯期檢測),代碼分析失暂。
如下:
1) 編寫文檔:通過代碼里標識的元數(shù)據(jù)生成文檔
2)代碼分析:通過代碼里標識的元數(shù)據(jù)對代碼進行分析
3)編譯檢查:通過代碼里標識的元數(shù)據(jù)讓編譯器能實現(xiàn)基本的編譯檢查
3.Java平臺元數(shù)據(jù)
注解Annotation就是java平臺的元數(shù)據(jù)彼宠,是 J2SE5.0新增加的功能鳄虱,該機制允許在Java 代碼中添加自定義注釋,并允許通過反射(reflection)凭峡,以編程方式訪問元數(shù)據(jù)注釋拙已。通過提供為程序元素(類、方法等)附加額外數(shù)據(jù)的標準方法摧冀,元數(shù)據(jù)功能具有簡化和改進許多應用程序開發(fā)領(lǐng)域的潛在能力倍踪,其中包括配置管理、框架實現(xiàn)和代碼生成索昂。
二建车、注解
注解的類型一般包括:元注解 、 Java內(nèi)置注解 & 自定義注解三種椒惨,下面我將解釋這三種注解使用方法癞志。
2.1元注解
JDK除了在java.lang提供了上述內(nèi)建注解外,還在java.lang框产。annotation包下提供了6個Meta Annotation(元Annotation),其中有5個元Annotation都用于修飾其他的Annotation定義错洁。其中@Repeatable專門用戶定義Java 8 新增的可重復注解秉宿。
@Documented
@Documented用戶指定被該元Annotation修飾的Annotation類將會被javadoc工具提取成文檔,如果定義Annotation類時使用了@Documented修飾屯碴,則所有使用該Annotation修飾的程序元素的API文檔中將會包含該Annotation說明描睦。
@Inherited
@Inherited指定被它修飾的Annotation將具有繼承性——如果某個類使用了@Xxx注解(定義該Annotation時使用了@Inherited修飾)修飾,則其子類將自動被@Xxx修飾导而。
@Retention
@Retention:表示該注解類型的注解保留的時長忱叭。當注解類型聲明中沒有@Retention元注解,則默認保留策略為RetentionPolicy.CLASS今艺。關(guān)于保留策略(RetentionPolicy)是枚舉類型韵丑,共定義3種保留策略,如下表:
@Target
@Target:表示該注解類型的所適用的程序元素類型虚缎。當注解類型聲明中沒有@Target元注解撵彻,則默認為可適用所有的程序元素。如果存在指定的@Target元注解实牡,則編譯器強制實施相應的使用限制陌僵。
@Repeatable
定義:可重復注解
2.2Java內(nèi)置注解
Java提供了多種內(nèi)建的注解,下面接下幾個比較常用的注解:@Override创坞、@Deprecated碗短、@SuppressWarnings以及@FunctionalInterface這4個注解。內(nèi)建注解主要實現(xiàn)了元數(shù)據(jù)的第二個作用:編譯檢查题涨。
@Override
用途:用于告知編譯器偎谁,我們需要覆寫超類的當前方法总滩。如果某個方法帶有該注解但并沒有覆寫超類相應的方法,則編譯器會生成一條錯誤信息搭盾。如果父類沒有這個要覆寫的方法咳秉,則編譯器也會生成一條錯誤信息。
@Override可適用元素為方法鸯隅,僅僅保留在java源文件中澜建。
@Deprecated
用途:使用這個注解,用于告知編譯器蝌以,某一程序元素(比如方法炕舵,成員變量)不建議使用了(即過時了)。
@SuppressWarnings
用途:用于告知編譯器忽略特定的警告信息跟畅,例在泛型中使用原生數(shù)據(jù)類型咽筋,編譯器會發(fā)出警告,當使用該注解后徊件,則不會發(fā)出警告奸攻。
注解類型分析: @SuppressWarnings可適合用于除注解類型聲明和包名之外的所有元素,僅僅保留在java源文件中虱痕。
@FunctionalInterface
用途:用戶告知編譯器睹耐,檢查這個接口,保證該接口是函數(shù)式接口部翘,即只能包含一個抽象方法硝训,否則就會編譯出錯。
2.3自定義注解
- 注解的定義
// 通過 @interface 關(guān)鍵字進行定義
// 形式類似于接口新思,區(qū)別在于多了一個 @ 符號
public @interface Test_Annotation {
}
- 注解的屬性
<-- 1. 定義 注解的屬性 -->
// 注解的屬性 在定義該注解本身時 進行定義
public @interface Test_Annotation {
// 注解的屬性 = 成員變量
// 注解只有成員變量窖梁,沒有方法
// 注解@Test_Annotation中有2個屬性:id 和 msg
int id();
String msg() default "Hello" ;
// 說明:
// 注解的屬性以 “無形參的方法” 形式來聲明
// 方法名 = 屬性名
// 方法返回值 = 屬性類型 = 8 種基本數(shù)據(jù)類型 + 類、接口夹囚、注解及對應數(shù)組類型
// 用 default 關(guān)鍵值指定 屬性的默認值纵刘,如上面的msg的默認值 = ”Hi“
}
<-- 2. 賦值 注解的屬性 -->
// 注解的屬性在使用時進行賦值
// 注解屬性的賦值方式 = 注解括號內(nèi)以 “value=”xx” “ 形式;用 ”荸哟,“隔開多個屬性
// 注解Test_Annotation 作用于A類
// 在作用 / 使用時對注解屬性進行賦值
@Test_Annotation(id=1,msg="hello")
public class A {
}
// 特別說明:若注解只有一個屬性彰导,則賦值時”value“可以省略
// 假設(shè)注解@Test_Annotation只有1個msg屬性
// 賦值時直接賦值即可
@Test_Annotation("hello")
public class A {
}
- 注解的使用
// 在類 / 成員變量 / 方法 定義前 加上 “@注解名” 就可以使用該注解
@Test_Annotation
public class Test {
@Test_Annotation
int a;
@Test_Annotation
public void print(){}
}
- 獲取注解
<-- 步驟1:判斷該類是否應用了某個注解 -->
// 手段:采用 Class.isAnnotationPresent()
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
<-- 步驟2:獲取 注解對象(Annotation)-->
// 手段1:采用getAnnotation() ;返回指定類型的注解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
// 手段2:采用getAnnotations() 敲茄;返回該元素上的所有注解
public Annotation[] getAnnotations() {}
三位谋、實例
1.定義注解
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int id();
String msg() default "測試";
}
2.添加注解
@TestAnnotation(id = 1, msg = "類注解")
public class Test {
@TestAnnotation(id = 2,msg = "變量注解")
int a;
@TestAnnotation(id = 3,msg = "方法注解")
public void print(){
System.out.println("方法打印");
}
}
3.運行時使用注解
public static void main(String[] args) {
Test test = new Test();
// 獲取類的對象
Class testClass = test.getClass();
// 反射獲取方法
Method[] methods = testClass.getDeclaredMethods();
for(Method m : methods){
// 判斷是否方法是否存在注解
if(m.isAnnotationPresent(TestAnnotation.class)){
try {
// 獲取方法和類的注解
TestAnnotation classAnnotation = Test.class.getAnnotation(TestAnnotation.class);
System.out.println("id = " + classAnnotation.id());
System.out.println("msg = " + classAnnotation.msg());
m.setAccessible(true);
m.invoke(test);
TestAnnotation methodAnnotation = m.getAnnotation(TestAnnotation.class);
System.out.println("id = " + methodAnnotation.id());
System.out.println("msg = " + methodAnnotation.msg());
}catch (InvocationTargetException e){
e.printStackTrace();
}catch (IllegalAccessException e){
e.printStackTrace();
}
}
}
// 輸出結(jié)果
id = 1
msg = 類注解
方法打印
id = 3
msg = 方法注解