1. 程式人生 > 其它 >JavaSE:註解

JavaSE:註解

技術標籤:JavaSEjava程式語言

註解

註解概念:說明程式的。給計算機看的
註釋概念:用文字描述程式的。給程式設計師看的

1.註解定義:

  • 註解(Annotation),也叫元資料。一種程式碼級別的說明。
  • 它是JDK1.5及以後版本引入的一個特性,與類、介面、列舉是在同一個層次。
  • 它可以宣告在包、類、欄位、方法、區域性變數、方法引數等的前面,用來對這些元素進行說明,註釋。

2.概念描述:

  • JDK1.5之後的新特性
  • 說明程式的
  • 使用註解:@註解名稱

3.作用分類:

  1. 編寫文件:通過程式碼裡標識的註解生成文件【生成文件doc文件】
  2. 程式碼分析:通過程式碼裡標識的註解對程式碼進行分析【使用反射】
  3. 編譯檢查:通過程式碼裡標識的註解讓編譯器能夠實現基本的編譯檢查【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:可以作用於成員變數上
  • @Retention:描述註解被保留的階段
    @Retention(RetentionPolicy.RUNTIME):當前被描述的註解,會保留到class位元組碼檔案中,並被JVM讀取

  • @Documented:描述註解是否被抽取到api文件中

  • @Inherited:描述註解是否被子類繼承
    (當註解類上加了@Inherited,那麼繼承了使用該註解的類的子類同時也會繼承父類的註解)
    在這裡插入圖片描述

7.在程式使用(解析)註解:獲取註解中定義的屬性值

  1. 獲取註解定義的位置的物件 (Class,Method,Field)

  2. 獲取指定的註解

    • getAnnotation(Class)
      其實就是在記憶體中生成了一個該註解介面的子類實現物件

       public class ProImpl implements Pro{
             public String className(){
                    return "cn.clearlast.annotation.Demo1";
             }
             public String methodName(){
                    return "show";
             }
       }
      
  3. 呼叫註解中的抽象方法獲取配置的屬性值

例項程式碼:

註解( 編寫註解類,將註解類新增到 測試類 類上。)

@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. 註解給誰用?
    1. 編譯器
    2. 給解析程式用
  3. .註解不是程式的一部分,可以理解為註解就是一個標籤