JavaSE:註解
阿新 • • 發佈:2021-02-17
註解
註解概念:說明程式的。給計算機看的
註釋概念:用文字描述程式的。給程式設計師看的
1.註解定義:
- 註解(Annotation),也叫元資料。一種程式碼級別的說明。
- 它是JDK1.5及以後版本引入的一個特性,與類、介面、列舉是在同一個層次。
- 它可以宣告在包、類、欄位、方法、區域性變數、方法引數等的前面,用來對這些元素進行說明,註釋。
2.概念描述:
- JDK1.5之後的新特性
- 說明程式的
- 使用註解:@註解名稱
3.作用分類:
- 編寫文件:通過程式碼裡標識的註解生成文件【生成文件doc文件】
- 程式碼分析:通過程式碼裡標識的註解對程式碼進行分析【使用反射】
- 編譯檢查:通過程式碼裡標識的註解讓編譯器能夠實現基本的編譯檢查【Override】
4.JDK中預定義的一些註解
- @Override :檢測被該註解標註的方法是否是繼承自父類(介面)的
- @Deprecated:該註解標註的內容,表示已過時
- @SuppressWarnings:壓制警告,一般傳遞引數all @SuppressWarnings(“all”)
5.自定義註解
格式:
元註解:用於描述註解的註解
元註解
public @interface 註解名稱{
屬性列表;
}
本質:註解本質上就是一個介面,該介面預設繼承Annotation介面
- public interface MyAnno extends java.lang.annotation.Annotation {}
屬性: 介面中的抽象方法
-
要求
-
屬性的返回值型別有下列取值
基本資料型別 String 列舉 註解 以上型別的陣列
-
定義了屬性,在使用時需要給屬性賦值
如果定義屬性時,使用default關鍵字給屬性預設初始化值,則使用註解時,可以不進行屬性的賦值。 如果只有一個屬性需要賦值,並且屬性的名稱是value,則value可以省略,直接定義值即可。 陣列賦值時,值使用{}包裹。如果陣列中只有一個值,則{}可以省略
6.元註解:用於描述註解的註解
-
@Target:描述註解能夠作用的位置
- ElementType取值:
- TYPE:可以作用於類上
- METHOD:可以作用於方法上
- FIELD:可以作用於成員變數上
- ElementType取值:
-
@Retention:描述註解被保留的階段
@Retention(RetentionPolicy.RUNTIME):當前被描述的註解,會保留到class位元組碼檔案中,並被JVM讀取 -
@Documented:描述註解是否被抽取到api文件中
-
@Inherited:描述註解是否被子類繼承
(當註解類上加了@Inherited,那麼繼承了使用該註解的類的子類同時也會繼承父類的註解)
7.在程式使用(解析)註解:獲取註解中定義的屬性值
-
獲取註解定義的位置的物件 (Class,Method,Field)
-
獲取指定的註解
-
getAnnotation(Class)
其實就是在記憶體中生成了一個該註解介面的子類實現物件public class ProImpl implements Pro{ public String className(){ return "cn.clearlast.annotation.Demo1"; } public String methodName(){ return "show"; } }
-
-
呼叫註解中的抽象方法獲取配置的屬性值
例項程式碼:
註解( 編寫註解類,將註解類新增到 測試類 類上。)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME )
public @interface Pro {
String className();
String methodName();
}
需要執行的類和方法( 將類名和方法名賦值到測試類 註解的屬性上 )
public class Demo1 {
public void show(){
System.out.println("Demo1...show");
}
}
測試類(利用反射的機制,通過類的反射獲取類上的註解Class物件)
@Pro(className = "annotation.Demo1",methodName = "show")
public class ReflectTest {
public static void main(String[] args) throws Exception {
/*
前提:不能改變該類的任何程式碼,可以建立任意類的物件,可以執行任意方法。
*/
//1.解析註解
//1.1獲取該類的位元組碼檔案物件
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//2.獲取上邊的註解物件
//其實就是在記憶體中生成了一個該註解介面的子類實現物件
Pro an = reflectTestClass.getAnnotation(Pro.class);
//3.呼叫註解物件中定義的抽象方法,獲取返回值
String className = an.className();
String methodName = an.methodName();
System.out.println(className);
System.out.println(methodName);
//3.載入該類進記憶體
Class cls = Class.forName(className);
//4.建立物件
Object obj = cls.newInstance();
//5.獲取方法物件
Method method = cls.getMethod(methodName);
//6.執行方法
method.invoke(obj);
}
}
執行結果:
annotation.Demo1
show
Demo1...show
案例:簡單的測試框架
案例程式碼:
註解
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}
測試類
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...");
}
}
簡單的測試框架
- 當主方法執行後,會自動自行被檢測的所有方法(加了Check註解的方法),判斷方法是否有異常,記錄到檔案中
- 通過 method物件可以呼叫getName()方法獲取方法名
- 通過 異常物件.getCause().getClass().getSimpleName() 獲取異常名稱
getCause()方法 是獲取異常的真實資訊
getClass()方法 獲取異常的Class物件
getSimpleName()方法 通過Class物件獲取異常的名稱 - 通過 異常物件.getCause().getMessage() 獲取異常的錯誤原因
public class TestCheck {
public static void main(String[] args) throws IOException {
//1.建立計算器物件
Calculator calculator = new Calculator();
//2.獲取位元組碼檔案物件
Class<Calculator> c = Calculator.class;
//3.獲取所有方法
Method[] methods = c.getMethods();
//出現異常的次數
int number = 0;
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) {
//4.判斷方法上是否有Check註解
if(method.isAnnotationPresent(Check.class)){
//5.有,執行
try{
method.invoke(calculator);
} catch (Exception e) {
//6.捕獲異常
number++;
//記錄到檔案中
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("本次一共出現了"+number+"次異常");
bw.flush();
bw.close();
}
}
小結:
- 以後大多數時候,我們會使用註解,而不是自定義註解
- 註解給誰用?
1. 編譯器
2. 給解析程式用 - .註解不是程式的一部分,可以理解為註解就是一個標籤