天天看點

Annotation(注解)注解

注解

1.概念:用來說明程式的,給計算機看的,注解(Annotation),也叫中繼資料。一種代碼級别的說明,它是jdk1.5及以後版本引入的一個特性,與類、接口、枚舉是在同一個層次。它可以聲明在包、類、字段、方法、局部變量、方法參數等的前面,用來對這些元素進行說明,注釋。

作用分類:

​ 編寫文檔:通過代碼裡辨別的中繼資料(注解)生成文檔(生成文檔doc文檔)

package annotation;


public class AnnoDemo1 {
    /**
     *
     * @param a 變量a
     * @param b 變量b
     * @return  a和b的和
     */
    public static int add(int a,int b){
        return a+b;
    }

    public static void main(String[] args) {
        System.out.println(add(3,5));
    }
}
           

Annotation(注解)注解

​ 代碼分析:通過代碼裡辨別的中繼資料(注解)對代碼進行分析(使用反射)

​ 編譯檢查:通過代碼裡辨別的中繼資料(注解)讓編譯器能夠實作基本的編譯檢查(Override)

2.JDK中預定義的一些注解

​ @Override:檢查被該注解标注的方法是否是繼承自父類(接口)的

​ @Deprecated:将該注解标注的内容表示為已過時

​ @SuppressWarnings:壓制警告 一般傳遞參數all @SuppressWarnings(“all”)

package annotation;
//@SuppressWarnings("all") //idea右側上的黃線警告消除
public class AnnoDemo2 {
    @Override
    public  String toString() {
        return "666";
    }

    @Deprecated
    public static void show(){
        System.out.println("過時!");
    }

    @SuppressWarnings("all")
    public void newshow(){

    }

    public static void main(String[] args) {
        show();//過時方法,劃了橫線
    }
}
           

3.自定義注解

​ 3.1格式:

元注解

	public @interface 注解名稱{
		屬性清單;
	}
           

​ 3.2本質:在dos視窗下對下面代碼進行編譯生成位元組碼檔案,然後利用 javap MyAnnotation.class反編譯這個位元組碼檔案得到其本質

public @interface MyAnnotation {
}
           

​ 即:注解本質上就是一個接口,該接口預設繼承java.long.annotation.Annotation接口

​ 3.3 屬性:接口中的抽象方法

​ 要求:

​ 3.3.1 屬性的傳回值類型:基本資料類型、String、枚舉、注解、以上資料類型的數組

package annotation;

public @interface MyAnnotation {
    int shwo1();
    String show2();//稱這個抽象方法就為注解的屬性
    Person p1();//枚舉類型
    MyAnnotation2 anno2();//注解類型
    String[] strs();
}
           

​ 3.3.2 定義了屬性,在使用時需要給屬性指派

​ 3.3.2.1如果定義屬性時,使用default關鍵字給屬性預設初始化值,則使用注解時,可以不進行屬性的指派否則必須在注解時指派,多個屬性指派用逗号隔開

public @interface MyAnnotation {
    int show1();
    String show2() default "666";//稱這個抽象方法就為注解的屬性
    MyAnnotation2 anno2();
    String[] strs();
}
           
@MyAnnotation(show1 = 1,anno2 = @MyAnno2,strs={"abc","bbb"})//定義了必須指派或者預設
public class AnnoDemo3 {
}
           

​ 3.3.2.2如果隻有一個屬性需要指派,并且屬性的名稱是value,則value可以省略,直接定義值即可

public @interface MyAnnotation {
    int value();
}
           
@MyAnnotation(1) //寫value不寫都可以
public class AnnoDemo3 {
}
           

​ 3.3.2.3數組指派時,值使用{ }包裹,如果數組中隻有一個值,則{ }可以省略

4.元注解:用于描述注解的注解

​ @Target:描述注解能夠作用的位置

​ ElementType的取值:

​ TYPE:可以作用于類上

​ METHOD:可以作用于方法上

​ FIELD:可以作用于成員變量上

@Target(value = {ElementType.TYPE})//表示該AnnoDemo3注解隻能作用于類上
public @interface AnnoDemo3 {
}

@AnnoDemo3//不報錯
class test{
    @AnnoDemo3//報錯
    public void show(){
        System.out.println("666");
    }
}
           

​ @Retention:描述注解被保留的階段

​ @Retention(RetentionPolicy.SOURCE):目前被描述的注解

​ @Retention(RetentionPolicy.CLASS):目前被描述的注解,會被保留到class位元組碼檔案中

​ @Retention(RetentionPolicy.RUNTIME):目前被描述的注解,會被保留到class位元組碼檔案中,并被JVM讀到

@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoDemo3 {
}
           

​ @Documented:描述注解是否被抽取到api文檔中

​ @Inherited:描述注解是否被子類繼承

5.在程式中使用(解析)注解:擷取注解中定義的屬性值

  1. 擷取注解定義位置的對象 (Class、Method、Field)
  2. 擷取指定的注解:getAnnotation(Class)
  3. 調用注解中的抽象方法擷取配置的屬性值(即注解中定義的抽象方法)
package annotation;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

/*
架構類
 要求:在不能改變該類的任意代碼下,可以建立任意類的對象,可以執行任意方法
         實作:1.配置檔案 2.反射
         步驟:
            1.将需要建立的對象的全類名和需要執行的方法定義在配置檔案中
            2.在程式中加載讀取配置檔案
            3.使用反射技術加載類檔案進記憶體
            4.建立對象
            5.執行方法
 */

@Pro(className = "annotation.Demo2",methodName = "show")
public class ReflectTest {
    public static void main(String[] args) throws Exception{
        //1.解析注解
        //1.1擷取該類的位元組碼檔案對象
        Class<ReflectTest> reflectTestClass = ReflectTest.class;
        //2.擷取上邊的注解對象
        //其實就是在記憶體中生成了一個該注解接口的子類實作對象
        /*
        public class zilei implements Pro{
            public String className(){
                return "annotation.Demo2";
            }
            public String methodName(){
                return "show";
            }
        }
         */
        Pro an = reflectTestClass.getAnnotation(Pro.class);
        //3.調用注解對象中定義的抽象方法(屬性),擷取傳回值
        String className = an.className();
        String methodName = an.methodName();
        //4.加載該類進記憶體
        Class cls = Class.forName(className);
        //5.建立對象
        Object obj = cls.newInstance();
        //6.擷取方法對象
        Method method = cls.getMethod(methodName);
        //7.執行方法
        method.invoke(obj);
    }
}
           
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
    String className();
    String methodName();
}
           
public class Demo1 {
    public void show(){
        System.out.println("demo1---show()");
    }
}
public class Demo2 {
    public void show(){
        System.out.println("demo2---show()");
    }
}
           

6.小案例—實作測試功能

check.java

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface check {

}
           

Calculator.java

package annotation.demo;
//簡單的電腦類
public class Calculator {
    //加法
    @check
    public void add(){
        System.out.println(1+0);
    }
    //減法
    @check
    public void jianfa(){
        System.out.println(1-0);
    }
    //乘法
    @check
    public void mul(){
        System.out.println(1*0);
    }
    //除法
    @check
    public void div(){
        System.out.println(1/0);
    }
}

           

TestCheck.java

package annotation.demo;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.lang.reflect.Method;

/*
測試架構

當主方法執行後,會自動執行被檢測的所有方法(即加check注解的),判斷方法是否能被正确執行
 */
public class TestCheck {
    public static void main(String[] args) throws Exception{
        //1.建立電腦對象
        Calculator c = new Calculator();
        //2.擷取位元組碼檔案對象
        Class cls = c.getClass();
        //3.擷取所有方法
        Method[] methods = cls.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(c);
                }catch(Exception e){
                    //6.捕獲異常
                    //記錄到檔案中
                    number++;
                    bw.write(method.getName()+"方法出異常了");
                    bw.newLine();
                    bw.write("異常的名稱:"+e.getCause().getClass().getSimpleName());
                    bw.newLine();
                    bw.write("異常的原因:"+e.getMessage());
                    bw.newLine();
                    bw.write("----------------");
                    bw.newLine();
                }
            }
        }
        bw.write("本次共出現了"+number+"次異常");
        bw.flush();
        bw.close();
    }
}
           

結果:

Annotation(注解)注解

7.注解的用途

  1. 用于讓編譯器知道
  2. 給解析程式用

繼續閱讀