Java注解 看這一篇就夠了


注解

1.概念

注解:說明程序的。給計算機看的

注釋:用文字描述程序的。給程序員看的

注解的定義:注解(Annotation),也叫元數據。一種代碼級別的說明。它是JDK1.5及以后版本引入的一個特性,與類、接口、枚舉是在同一個層次。它可以聲明在包、類、字段、方法、局部變量、方法參數等的前面,用來對這些元素進行說明,注釋。

2.作用

①編寫文檔:通過代碼里標識的注解生成文檔【生成文檔doc文檔】:

​ shift+右鍵 -> 在此處打開Powershell窗口 -> 輸入:javadoc .\類名.java

②代碼分析:通過代碼里標識的注解對代碼進行分析【使用反射】

③編譯檢查:通過代碼里標識的注解讓編譯器能夠實現基本的編譯檢查【Override】

3.Java 的三大注解

1.@Override:表明子類中覆蓋了超類中的某個方法,如果寫錯了覆蓋形式,編譯器會報錯

2.@deprecated:廢棄的(過時的)表明不希望別人在以后使用這個類,方法,變量等.

3.@suppresswarnings:抑制警告

​ 達到抑制編譯器產生警告的目的,但是不很不建議使用,因為后期編碼人員看不懂編譯器 提示的警告,不能更好的選擇更好的類去完成任務。

​ 一般傳遞參數:all @SuppressWarnings("all") 可以加在類的上面一行,這樣代碼就 沒有警告了,顯得比較干凈。

4.自定義注解:

本質:注解本質上就是一個接口,該接口默認繼承Annotation接口

​ public interface MyAnno extends java.lang.annotation.Annotation {}

​ 可以在Powershell窗口反編譯看看:

格式:

public @interface 注解名稱{
/* 屬性列表;
 * 注解中的屬性 主要定義抽象方法 不定義常量
 * 抽象方法的返回值類型有要求():
 * 		1.基本數據類型
 * 		2.String
 * 		3.枚舉類型
 * 		4.注解
 * 		5.數組(以上幾種類型的數組)
 */
}
//屬性列表中抽象方法的舉例:
public @interface MyAnno {
	
	 int getName();
	  
	 String getStr();
	  
	 Season getSeason();   //新建Enum枚舉類Season
	  
	 MyAnno2 getMyAnno2();	//新建Annotation注解類MyAnno2
	
	String[] value();
	
	//int getName() default 0;  //如果不想為注解中的某個屬性賦值,可以為其定義默認值

}
//枚舉類
public enum Season {
	SPRING,SUMMER,AUTUMN,WINtER
}

注解類定義了屬性,那么在使用時必須給屬性賦值。

/*
1. 如果定義屬性時,使用default關鍵字給屬性默認初始化值,則使用注解時,可以不進行屬性的賦值。int getName() default 0;
	@MyAnno()
	public static void  test02() {}
2. 如果只有一個屬性需要賦值,並且屬性的名稱是value,則value可以省略,直接定義值即可。

3. 數組賦值時,值使用{}包裹。如果數組中只有一個值,則{}可以省略。
*/
//對我們自定義的MyAnno注解類的使用:
@MyAnno(getName = 1, getStr = "100", getSeason = Season.SPRING, getMyAnno2= @MyAnno2,value = {"1","2"})
public static void  test01() {}

元注解:用於描述注解的注解(注解前面的注解)

@Target:描述注解能夠作用的位置
	ElementType取值:
		TYPE:可以作用於類上
         FIELD:可以作用於成員變量上
		METHOD:可以作用於方法上
@Retention:描述注解被保留的階段
	SOURCE:	源代碼階段, 被編譯器忽略
	CLASS:  注解將會被保留在Class文件中,但在運行時並不會被VM保留。這是默認行為,所有沒			有用Retention注解的注解,都會采用這種策略。
	RUNTIME:保留至運行時。所以我們可以通過反射去獲取注解信息。
	@Retention(RetentionPolicy.RUNTIME):當前被描述的注解,會保留到class字節碼文件中,並被JVM讀取到
//下面兩個了解
@Documented:描述注解是否被抽取到api文檔中
@Inherited:描述注解是否被子類繼承

對Java的三大注解之一的SuppressWarnings注解進行分析:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();      //只有一個屬性,且名稱為value,且為數組賦值
}
@SuppressWarnings(value={"all"})	
public class AnnoTest {}
//同樣可以這么使用
@SuppressWarnings({"all"})	//使用時可以省略value
@SuppressWarnings("all")	//使用時可以省略{}

5.注解的使用

注解的作用:將我們為注解中的屬性(抽象方法)賦的值提取出來,在類中使用

  1. 獲取注解定義的位置的對象 (Class,Field,Method)

  2. 獲取指定的注解:

    getAnnotation(Class annotationClass):方法返回該元素的指定類型的注釋,如果是這樣的注釋,否則返回null

    ​ 參數:annotationClass -- 對應於注釋類型的Class對象。

6.案例

1.定義該類使用注解加反射,實現不修改任何代碼(只需要修改注解中的值),就可以實現調用任意類中的任意方法

//自定義注解類
@Retention(RUNTIME)
@Target(TYPE)
public @interface Pro {
	
	String className();   //通過該屬性獲取到類名
	String methodName();   //通過該屬性獲取到方法名

}
@SuppressWarnings("all")
@Pro(className = "com.huike.b.useanno.Demo2", methodName = "show")
public class AnnoTest {
	
	public static void main(String[] args) throws Exception {
		
		//1.解析注解
		//1.1:獲取加注解的類的字節碼文件對象
		//1.2:獲取注解對象
		Class cls = AnnoTest.class;
		
		//通過當前類的Class對象獲取到類上的注解對象
		Pro pro = (Pro) cls.getAnnotation(Pro.class);
		
		
		//2.調用注解中的抽象方法  獲取到返回值
		String className = pro.className();
		String methodName = pro.methodName();
		
		//3.獲取到返回值所對應的類的Class對象
		Class cls1 = Class.forName(className);	
		
		//4.創建該類的對象
		Object object = cls1.newInstance();
		
		//5.獲取到該類的特定方法對象
		Method method = cls1.getMethod(methodName);
		
		//6.執行方法
		method.invoke(object);
		
	}
}

2.測試框架:

  •  當main方法執行后,會自動執行被檢測的所有方法(被加了Check注解的方法),判斷方法內是否有異常
    
  •  如果沒有就算了,如果有異常,會自動記錄到特定的文件中,文件中記錄哪些方法出異常了,異常的名稱是什么異常的原因是什么   
    
  •  得出總結:本次共測試了多少方法,出現了多少次異常
    
//Check注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
}
//自定義Calculator類,被用於測試
public class Calculator {
	
	//加法
	@Check
	public void add() {
		String str = null;
		str.toString();
		System.out.println("1 + 0="+(1 + 0));
	}
	
	//減法
	@Check
	public void sub() {
		System.out.println("1 - 0="+(1 - 0));
	}
	
	//乘法
	@Check
	public void mul() {
		System.out.println("1 * 0="+(1 * 0));
	}
	
	//除法
	@Check
	public void div() {
		System.out.println("1 / 0="+(1 / 0));
	}
	
	public void show() {
		System.out.println("永無bug...");
	}
	
}

//測試類
public class CheckDemo {
	
	public static void main(String[] args) throws Exception{
		
		//1.創建計算器對象 得到對應的Class對象
		Calculator c = new Calculator();
		Class cls = c.getClass();
		//2.獲取到該對象中的所有的方法
		Method[] methods = cls.getDeclaredMethods();
		
		int num01 = 0;  //定義一個int類型的值用於記錄出現的異常次數
		int num02 = 0;  //定義一個int類型的值用於記錄帶有Check注解的方法數
		BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
		
		//3.判斷哪些方法上有Check注解
		for (Method method : methods) {
			
			//該方法用於判斷 方法上是否有特定的注解
			//4.如果有Check注解,執行該方法 如果該方法無任何異常,就算了
			if (method.isAnnotationPresent(Check.class)) {
				num02++;
				try {
					method.invoke(c);   //如果有注解,則執行該方法
				} catch (Exception e) {
					num01++;
					//5.如果有異常,記錄異常信息,並通過IO流打印到文件中
					//如果方法存在異常 需要在此通過IO流捕獲
					bw.write(method.getName()+" 方法出異常了...");
					bw.newLine();
					//獲取到異常的簡短名稱
					bw.write("異常的名稱為:"+ e.getCause().getClass().getSimpleName());
					bw.newLine();
					bw.write("異常的原因是:"+ e.getCause().getMessage());
					bw.newLine();
					bw.write("------------------------------------------------");
					bw.newLine();
				}
				
			}
		}
		
		bw.write("本次測試結束了,一共測試了"+num02+"個方法,共出現了"+num01+"次異常!");
		bw.flush();
		bw.close();
		
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM