java高級之註解

註解

註解的概念

註解是JDK1.5的新特性。

  • 註解相當一種標記,是類的組成部分,可以給類攜帶一些額外的信息。
  • 註解可以加在包,類,字段,方法,方法參數以及局部變量上。
  • 註解是給編譯器看的,編譯器可以根據註解來完成對應的功能。

註解的作用:給程序帶入參數。

註解的定義格式

	修飾符 @interface 註解名{
         屬性
    }

註解屬性的定義格式

  • 格式1:數據類型 屬性名(); 沒有默認值的,使用時必須賦值。
  • 格式2:數據類型 屬性名() default 默認值; 有默認值的,使用時如果不賦值就會使用默認值,如果賦值就會覆蓋掉默認值。

註解中能夠定義什麼類型的屬性

  • 8種基本數據類型。
  • String類型。
  • Class類型。
  • enum類型。
  • 註解類型。
  • 以及上面所有的一維數組類型。

自定義註解

//自定義註解代碼,上面這兩個元註解後面會說到
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    //String類型屬性
    String name();

    //int類型屬性
    int age() default 20;

    //String數組類型屬性
    String[] works();
}

註解使用的注意事項

  1. 空註解可以直接使用。
  2. 一個對象中不能連續使用同一個註解多次,但是一個對象中可以使用多個不同的註解。
    (不同的位置可以使用一樣的註解,但是同樣的位置不能使用一樣的註解)
  3. 使用帶有屬性註解的時候,註解中的屬性一定要賦值,如果有多個屬性,用(逗號)隔開,如果註解中的屬性有數組,那麼如果數組只有一個元素值,那麼{}不用寫,反之用寫。
  4. 如果註解中的屬性值有默認值,那麼我們不必要寫,也不用重新賦值,反之必須寫上。
  5. 如果註解中只有一個屬性,並且屬性名叫value,那麼使用註解的時候,屬性名不用寫。

註解的解析

註解的解析就是獲取註解中的屬性值。

需要用到的接口:

  • AnnotatedElement

需要用到的方法:

  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判斷該對象上是否存在指定的註解,傳遞的參數是 註解.class
  • Annotation getAnnotation(Class annotationClass):返回該註解對象,傳遞什麼類型,返回什麼類型,傳遞的參數是 註解.class

代碼演示:


//自定義註解代碼,上面這兩個元註解後面會說到
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    //String類型屬性
    String name();

    //int類型屬性
    int age() default 20;

    //String數組類型屬性
    String[] works();
}


//測試代碼
//使用註解並賦值參數,有默認值的可以不賦值,如果本身有默認值,再次賦值會覆蓋掉默認值
@MyAnnotation(name="豬皮",works={"寫代碼","測試代碼"})
public class Test {
    public static void main(String[] args)throws Exception {
        //獲取當前類對象的Class對象
        Class c = Class.forName("cn.it.Work1.Test");

        //判斷當前類對象上是否有該註解
        if(c.isAnnotationPresent(MyAnnotation.class)){
            //如果有就獲取當前註解對象
            MyAnnotation m = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
            //輸出屬性內容
            System.out.println(m.name());
            System.out.println(m.age());
            //遍歷數組元素
            for (String work : m.works()) {
                System.out.println(work);
            }
        }
    }
}

測試結果:

豬皮
20
寫代碼
測試代碼

元註解

元註解的作用:

  • 控制自定義的註解可以寫在哪裏,(類,方法,變量上,包…)
  • 控制自定義註解的生命週期

元註解1:@Target (作用域)

@Target 作用: 指定註解可出現的位置。

  1. 點進@Target底層發現,底層是 ElementType[] value(); 數組,可以賦值多個。
  2. 點進ElementType底層發現,底層的 ElementType的數據類型,是枚舉,枚舉的屬性,都是靜態修飾,直接類名調用。

ElementType中的屬性:

  • TYPE:註解可以寫在類上
    
  •  FIELD:註解可以寫在成員變量上
    
  •  METHOD:註解可以寫在方法上
    
  •  PARAMETER:註解可以寫在方法參數上
    
  •  CONSTRUCTOR:註解可以寫在構造方法上
    

注意:如果自定義註解的時候,不加該註解 (@Target) 那麼默認就是在什麼上面都可以使用。

元註解2:@Retention (生命週期)

@Retention 作用:指定註解的聲明週期。
1.點到Retention底層發現,底層的 RetentionPolicy value(); 不是數組,只能賦值一個。
2.點到RetentionPolicy底層發現,底層的 RetentionPolicy數據類型是枚舉,枚舉的屬性,都是靜態修飾,直接類名調用。

RetentionPolicy中的屬性:

  • SOURCE(默認級別) 註解僅存在於源碼中的java文件中(不在class文件中,也不在方法區中)。
  • CLASS 註解存在於編譯後的class文件中->Class文件中出現了,方法區中沒有。
  • RUNTIME 註解存在於運行時期的內存中–>方法區中出現了,一旦在方法區中出現了,我們才能利用反射獲取到註解。

案例演示:

要求:模仿Junit中的@Test,讓帶有該註解的方法執行。


//定義一個空註解 MyTest
@Retention(RetentionPolicy.RUNTIME)  //生命週期是運行時期生命週期
@Target(ElementType.METHOD)  //只能作用在方法上
public @interface MyTest {
}



//測試
public class Work2 {
    public static void main(String[] args)throws Exception {
    	//獲取Work2的Class類對象
        Class c = Work2.class;
        //根據Class類對象獲取所有public方法
        Method[] methods = c.getMethods();
        //根據Class對象獲取當前類對象
        Object o = c.newInstance();

		//循環遍歷所有的方法
        for (Method method : methods) {
        	//判斷如果存在 @MyTest 註解就返回 true
            boolean flag = method.isAnnotationPresent(MyTest.class);
            if (flag){
            	//執行方法
                method.invoke(o);
            }
        }
    }

    @MyTest
    public void method1(){
        System.out.println("我是method1");
    }
    @MyTest
    public void method2(){
        System.out.println("我是method2");
    }

    public void method3(){
        System.out.println("我是method3");
    }
}

測試結果:帶 @MyTest 註解的方法都被執行了。

我是method1
我是method2

註解解析案例:

//指的是作用在類上和方法上,如果不配置的話默認是在任何地方都可以使用
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)  //存在於運行時期的內存中
public @interface MyPerson {
    String name();

    //有默認值的
    float salary() default 2500.f;

    int[] number();
}


//如果給數組賦值時,只有一個值不需要{},如果兩個值要加上{}
@MyPerson(name = "豬皮",number = {1,2})
public class MyPersonTest {
    public static void main(String[] args)throws Exception {
        System.out.println("=============使用當前類對象對註解進行解析=============");
        //獲取類的Class對象
        Class c = MyPersonTest.class;
        //判斷該類上是否包含指定註解
        boolean flag = c.isAnnotationPresent(MyPerson.class);

        if (flag) {
            //如果有該註解,就獲取該註解對象,並且強轉成該類型
            MyPerson mp = (MyPerson) c.getAnnotation(MyPerson.class);

            //輸出屬性
            System.out.println(mp.name());
            System.out.println(mp.salary());
            for (int i : mp.number()) {
                System.out.println(i);
            }
        }

        System.out.println("=============使用Method對象對註解進行解析=============");

        method();
    }

    @MyPerson(name = "奧哥",salary = 3000.f,number = 5)
    public static void method() throws Exception{
        //獲取類的Class對象
        Class c = MyPersonTest.class;
        //獲取方法的Class對象
        Method method = c.getMethod("method");

        //判斷***方法***上是否包含MyPerson註解
        if (method.isAnnotationPresent(MyPerson.class)){
            //獲取MyPerson註解中的屬性
            MyPerson mp = method.getAnnotation(MyPerson.class);

            //輸出屬性
            System.out.println(mp.name());
            System.out.println(mp.salary());
            for (int i : mp.number()) {
                System.out.println(i);
            }
        }
    }
}

測試結果:使用不同的對象,解析不同作用域的註解

=============使用當前類對象對註解進行解析=============
豬皮
2500.0
1
2
=============使用Method對象對註解進行解析=============
奧哥
3000.0
5

如果有缺少的地方,請各位指點,我在加上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章