1. 程式人生 > 實用技巧 >Java 註解用法

Java 註解用法

Java 註解用法

1、簡述

Annontation是Java5開始引入的新特徵。中文名稱一般叫註解。它提供了一種安全的類似註釋的機制,用來將任何的資訊或元資料(metadata) 與程式元素(類、方法、成員變數等)進行關聯。

Annontation像一種修飾符樣,應用於包、型別、構造方法、方法、成員變數、引數及本地變數的宣告語句中。

2、基本Annontation

  • java提供五個基礎的annontation型別

    • @Override

      • 此註解作用於方法,作用於此方法的註解,意味此方法受重寫規則的約束,否則不能編譯成功

    • @Deprecated

      • 作用於方法,標註此方法過時

    • @SuppressWarnings

      • 對於某些不想看到的警告資訊,可以通過這個註解來遮蔽

    • @SafeVarargs

      • 抑制型別轉換異常的警告資訊,只能用在引數長度可變的方法或構造方法上,且方法必須宣告為static或final,否則會出現編譯錯誤。一個方法使用@SafeVarargs註解的前提是,開發人員必須確保這個方法的實現中對泛型型別引數的處理不會引發型別安全問題。

    • @FunctionalInterface

      • Java 8為函式式介面引入的一個新註解,主要用於編譯級錯誤檢查,加上該註解,當你寫的介面不符合函式式介面定義的時候,編譯器會報錯。保證該介面只能包含一個抽象方法

3、自定義註解

參考資料:https://www.jianshu.com/p/9471d6bcf4cf

4、getAnnotation方法

  • 獲取作用於元素上的單個註解物件

4.1、獲取類註解屬性值

/**
* 自定義註解
*/
@Retention(RetentionPolicy.RUNTIME)//生命週期
@Target(ElementType.TYPE)//作用範圍
public @interface Myannontation {
String value();
}

/**
* 將自定義註解作用在People類
*/
@Myannontation("people")
public class People {

}

/**
* 測試類
*/
public class Test {

public static void main(String[] args) throws ClassNotFoundException {
//獲取Class物件
Class peopleClass=Class.forName("com.yl.annontation.People");
//獲取註解
Myannontation myannontation= (Myannontation) peopleClass.getAnnotation(Myannontation.class);
//獲取註解值
String value=myannontation.value();
System.out.println(value);
}

}

4.2、獲取方法註解屬性值

/**
* 自定義註解
*/
@Retention(RetentionPolicy.RUNTIME)//生命週期
@Target(ElementType.METHOD)//作用範圍
public @interface Myannontation {
String value();
}

/**
* 將自定義註解作用在show方法
*/

public class People {

@Myannontation("show")
public void show(){}
}

/**
* 測試類
*/
public class Test {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//獲取Class物件
Class peopleClass=Class.forName("com.yl.annontation.People");
//獲取show方法
Method showMethod=peopleClass.getMethod("show");
//獲取註解
Myannontation myannontation= (Myannontation) showMethod.getAnnotation(Myannontation.class);
//獲取註解值
String value=myannontation.value();
System.out.println(value);
}

}

4.3、獲取屬性註解屬性值

/**
* 自定義註解
*/
@Retention(RetentionPolicy.RUNTIME)//生命週期
@Target(ElementType.FIELD)//作用範圍
public @interface Myannontation {
String value();
}

/**
* 將自定義註解作用在屬性
*/

public class People {
@Myannontation("name")
public String name;
}

/**
* 測試類
*/
public class Test {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
//獲取Class物件
Class peopleClass=Class.forName("com.yl.annontation.People");
//獲取name屬性
Field nameField=peopleClass.getField("name");
//獲取註解
Myannontation myannontation= (Myannontation) nameField.getAnnotation(Myannontation.class);
//獲取註解值
String value=myannontation.value();
System.out.println(value);
}

}

5、getAnnotations方法

  • 獲取作用於元素上的所有註解物件,包括父類註解

/**
*自定義註解1
*/
@Retention(value=RetentionPolicy.RUNTIME)//生命週期
@Target({ElementType.METHOD})//作用範圍
@interface Anno{
//定義一個成員
String value();
}

/**
*自定義註解2
*/
@Retention(value=RetentionPolicy.RUNTIME)//生命週期
@Target({ElementType.METHOD})//作用範圍
@interface Anno2{
//定義一個成員
String value();
}

/**
*將自定義註解作用在方法上
*/
class MyTest{
@Anno(value="張三")
@Anno2(value="李四")
public void info(){}
}

public class MainTest {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
//獲取MyTest類的Class物件
Class<MyTest> myTestCls=(Class<MyTest>) Class.forName("getannotation方法使用.MyTest");
//獲取info方法的物件
Method infoM=myTestCls.getMethod("info", null);
//獲取作用於元素上的所有註解物件
Annotation[] annotatinArrays=infoM.getAnnotations();
//遍歷annotatinArrays
for(Annotation annoObj:annotatinArrays){
if(annoObj instanceof Anno){
System.out.println("註解的元資料值="+((Anno)annoObj).value());
}else if(annoObj instanceof Anno2){
System.out.println("註解的元資料值="+((Anno2)annoObj).value());
}
}
}

}

6、isAnnotationPresent方法

  • 此方法判斷元素是否作用註解,如果此方法作用於此註解,則返回true,否則返回false

/**
*自定義註解
*/
@Retention(value=RetentionPolicy.RUNTIME)//生命週期
@Target({ElementType.METHOD})//作用範圍
@interface Anno{
//定義一個成員
String value();
}

/**
*自定義註解
*/
@Retention(value=RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@interface Anno2{
//定義一個成員
String value();
}

class MyTest{
public void info(){}

public void info2(){}

@Anno(value="張三")
public void info3(){}
}

public class MainTest {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
//獲取MyTest類的Class物件
Class<MyTest> myTestCls=(Class<MyTest>) Class.forName("getannotation方法使用.MyTest");
//獲取info方法的物件
Method infoM=myTestCls.getMethod("info", null);
System.out.println(infoM.isAnnotationPresent(Anno.class));//fasle
}

}

7、getDeclaredAnnotations方法

  • 返回直接存在於此元素上的註解,即不包括從父類繼承過來的註解。比較簡單理解,不寫程式碼案例了。

8、@Retention

@Retention是Java 1.8 才加進來的,所以算是一個新的特性

Repeatable的英文意思是可重複的。顧名思義說明被這個元註解修飾的註解可以同時作用一個物件多次,但是每次作用註解又可以代表不同的含義。

下面我們看一個人玩遊戲的例子

/**一個人喜歡玩遊戲,他喜歡玩英雄聯盟,絕地求生,極品飛車,塵埃4等,則我們需要定義一個人的註解,他屬性代表喜歡玩遊戲集合,一個遊戲註解,遊戲屬性代表遊戲名稱*/
/**玩家註解*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface People {
Game[] value() ;
}

/**遊戲註解*/
@Repeatable(People.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Game {
String value();
}

/**玩遊戲類*/
@Game(value = "LOL")
@Game(value = "PUBG")
@Game(value = "NFS")
@Game(value = "Dirt4")
public class PlayGame {
}

/**
*測試類,獲取註解屬性值
*/
public static void main(String[] args) throws ClassNotFoundException {
//獲取Class物件
Class playClass=Class.forName("com.yl.annontation.PlayGame");
//獲取註解
People people= (People) playClass.getAnnotation(People.class);
//獲取註解值
Game[] value=people.value();
//輸出註解值
System.out.println(Arrays.toString(value));
}
/**
*@Game會存入@People的Game[]中
*@Game必須要有一個屬性名為value,@People也是
*/

9、編譯時處理Annotation

處於RetentionPolicy.CLASS生命週期的註解資訊,如何提取?

問題就是當處理CLASS階段的註解資訊,會在執行期間之前就丟失,因此不能通過執行期間的反射機制提取資料

但是可以通過APT工具,在javac期間提取處於編譯時的註解資料資訊

具體如何實現

/**
*建立一個處於編譯期間的註解
*/
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface MyAnno {
String value();
}

/**
*註解作用於類
*/
@MyAnno(value="red apple")
public class Apple {}

@SupportedSourceVersion(SourceVersion.RELEASE_8)//設定jdk版本
@SupportedAnnotationTypes("apt.MyAnno") //設定自定義註解
public class MyAnnotationProcess extends AbstractProcessor {

/**
*重寫核心方法:註解處理器,當javac呼叫apt工具觸此處理器
*/
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
//獲取根節點資訊
for (Element rootElement : roundEnv.getRootElements()) {
//如果此根節點標註註解資訊並且屬於類
if(rootElement.getKind()== ElementKind.CLASS) {
//獲取註解類物件
MyAnno annTest=rootElement.getAnnotation(MyAnno.class);
if(annTest!=null) {
System.out.println("將編譯時的註解元 資料提取="+annTest.value());
}
}
}
return false;
}
}

如何通過apt編譯

  • javac -d . MyAnnotationProcess.java

  • javac -d . *.java -processor apt.MyAnnotationProcess

最終輸出結果