1. 程式人生 > 其它 >第十九天 註釋

第十九天 註釋

技術標籤:javajava

定義

  • 註解,亦叫做註釋,英文單詞:Annotation
  • 註解Annotation是一種引用資料型別,編譯之後也是生成xxx.class檔案
  • 怎麼樣自定義註解?語法格式是啥?
[ 修飾符列表 ] @interface 註解型別名{ }
  • 使用註解的語法格式:
@註解型別名
  • 註解用在什麼地方法
    • 註解可以用在類上、屬性上、方法上、變數上…
    • 註解甚至能出現在註解型別上

註解類

public @interface MyAnnotation {
}

註解使用的位置

package Day19註解;

public class Test01 {
    @MyAnnotation
//屬性 private int no; @MyAnnotation //構造方法 public Test01() {} @MyAnnotation //靜態方法 public static void doSome(){} @MyAnnotation //例項方法 public void doOther(){ @MyAnnotation //區域性變數 int i = 1; } public void m1(@MyAnnotation String name)
{} //形參 } @MyAnnotation //介面 interface MyInterface{} @MyAnnotation //列舉 enum Season{ SPRING,SUNMER,AUTUMN,WINTER }

package Day19註解;

@MyAnnotation       //其他註釋
public @interface OtherAnnotation {
}

綜上所述:註釋能出現在:屬性、構造方法、靜態方法、例項方法、區域性變數、介面、列舉型別、其他註釋上

Override註解

註解型別描述
Deprecated一個程式單元註釋”不是一個程式設計師應該使用,通常是因為它是危險的,因為一個更好的選擇的存在。
Override表示一個方法宣告的目的是覆蓋父類方法宣告。
SuppressWarnings指示在註釋元素(和包含在註釋元素中的所有程式元素中)應被抑制命名的編譯器警告。

Override註解

package Day19註解;

public class Test02 {
    /*
    Override的原始碼:
        @Target(ElementType.METHOD)
        @Retention(RetentionPolicy.SOURCE)
        public @interface Override {}
    * */

    @Override
    public String toString() {
        return "toString";
    }
}

解釋:
@Override這個註解只能註解方法
該註解是給編譯器參考的,和執行階段沒有關係,如果java中的方法帶有這個註解,編譯器就會進行編譯檢查,如果該方法沒有重寫父類的方法,則報錯

元註解

  • 定義:標註“註解型別”的註解
  • 常見的元註解
    • Target
    • Retention
  • Target
    • 這是一個元註解,用來標註“註解型別”的註解
    • 作用:限制被標註的註解出現的位置
    • 例項
@Target(ElementType.METHOD)
//表示被該註解標註的註解只能出現在方法上
  • Retention
    • 標註“被標註的註解”最終儲存在哪裡
    • 例項
@Retention(RetentionPolicy.SOURCE)
//表示該註解只是被保留在Java原始檔中

@Retention(RetentionPolicy.CLASS)
//表示該註解被儲存在class檔案中

@Retention(RetentionPolicy.RUNTIME)
//表示該註解被儲存在class檔案中,並且可以被反射機制所讀取

Deprecated註解

作用:告訴其他人這個東西已經過時了,目前已經有了更好的解決方案

package Day19註解;

@Deprecated
public class Test03 {
    public static void main(String[] args) {
        Test03 test03 = new Test03();
        test03.doSome();
    }

    @Deprecated
    public static void doSome(){
        System.out.println("do Something...");
    }

    public static void doOther(){
        System.out.println("do Other thing...");
    }
}

class Test04{
    public static void main(String[] args) {
        Test03 test03 = new Test03();
        test03.doOther();

        try {
            Class<?> aClass = Class.forName("Day19註解.Test03");
            Object object = aClass.newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-wC73NyzH-1612032291499)(en-resource://database/708:1)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-s2ZWQoiH-1612032291501)(en-resource://database/710:1)]

表示該方法和該類均被淘汰了

註解定義屬性

自定義屬性

package Day19註解;

public @interface MyAnnotation {
    String name();

    String color();

    int age = 21;   //屬性指定預設值
}

測試

package Day19註解;

public class Test05 {
//    @YourAnnotation()
//    public void doSome(){}
//    對於元素name,color, 註釋 @Day19註解.YourAnnotation 缺少預設值

    @YourAnnotation(name = "張三", color = "black")
    public void doSome(){}

    public static void main(String[] args) {}


}

注意事項:

  1. 在註解中也是可以定義屬性的
  2. 雖然屬性後面有個小括號,看著很像是方法,但是這實際上就是註釋的屬性
  3. 如果註解中有屬性,則必須給屬性賦值,除非本身就使用default指定了預設值
屬性是value的時候

當註解僅有一個value屬性的時候:
註解類:

package Day19註解;

public @interface YourAnnotation2 {
    String value();
}

測試:

package Day19註解;

public class Test06 {

    @YourAnnotation2(value = "張三")
    public void doSome(){}

    @YourAnnotation2("李四")
    public void doOther(){}

    public static void main(String[] args) {}
}

注意事項:
當註釋中僅有一個屬性,且該屬性的名字是value的時候,在呼叫該註釋的時候,小括號中的“value = ”可以直接省略

當註釋不僅僅有一個value屬性的時候
註解類:

package Day19註解;

public @interface YourAnnotation3 {
    String value();

    String name();
}

測試:

package Day19註解;

public class Test07 {

    @YourAnnotation3(value = "李四", name = "張三")
    public void doSome(){}

    public static void main(String[] args) {}
}

注意事項:
當先將“value = ”省略的時候,去填name,IDEA會自動的將“value = ”加上,如果沒有,則會報錯

屬性是一個數組

  • 註解的屬性型別可以是:byte short int long float double boolean char String Class 列舉型別
package Day19註解;

public @interface MyAnnotation2 {
    int value1();

    String value2();

    int[] value3();

    String value4();

    Season value5();

    Season[] value6();

    Class parameterType();

    Class[] parameterTypes();
}

列舉:

package Day19註解;

public enum Season2 {
    SPRING,SUMMER,AUTUMN,WINTER
}

屬性為列舉型別:

package Day19註解;

public @interface MyAnnotation3 {
    int age();
    
    String[] name();
    
    Season[] seasonArray();
}

測試:

package Day19註解;

public class Test08 {
    @MyAnnotation3(age = 21, name = {"張三", "李四"}, seasonArray = {Season.AUTUMN,Season.SPRING})
    public void doSome(){}


    @MyAnnotation3(age = 21, name = "張三", seasonArray = {Season.AUTUMN,Season.SPRING})
    public void doOther(){}
}

注意事項:

  1. 列舉型別的屬性寫入的時候,需要加列舉型別的名字
  2. 如果陣列只有1個元素,大括號是可以省略的

反射註解

自定義註解:

package Day19註解;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//該註解只能標記類和方法
@Target({ElementType.TYPE,ElementType.METHOD})
//該註解可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation4 {
    String value() default "廣東廣州";
}

測試註解:

package Day19註解;

@MyAnnotation4("四川成都")
public class Test09 {
//    @MyAnnotation4("四川成都")    //因為Target標註限制,所以MA4註釋不能註釋屬性
    int i;

//    @MyAnnotation4("四川成都")    //因為Target標註限制,所以MA4註釋不能註釋構造方法
    public Test09(){}

    @MyAnnotation4("四川成都")
    public void doSome(){
//        @MyAnnotation4("四川成都")    //因為Target標註限制,所以MA4註釋不能註釋區域性變數
        int i;
        System.out.println("doSome...");
    }
}

通過反射獲取類的註釋

package Day19註解;

public class Test10 {
    public static void main(String[] args) throws ClassNotFoundException {
        //獲取類
        Class<?> t9Class = Class.forName("Day19註解.Test09");

        //判斷該類上是否存在MyAnnotation4註釋
        if (t9Class.isAnnotationPresent(MyAnnotation4.class)){
            //獲取該註釋物件
            MyAnnotation4 t9ClassAnnotation = t9Class.getAnnotation(MyAnnotation4.class);
            //輸出該註釋物件
            System.out.println(t9ClassAnnotation);

            //獲取註釋物件的屬性值
            String value = t9ClassAnnotation.value();
            //輸出屬性
            System.out.println(value);
        }

        //對比實驗,判斷String類上面有無@MyAnnotation4
        //獲取類
        Class<?> aClass = Class.forName("java.lang.String");
        if (aClass.isAnnotationPresent(MyAnnotation4.class)){
            System.out.println(aClass.getAnnotation(MyAnnotation4.class));
        } else {
            System.out.println(aClass.getSimpleName() + "型別不存在MyAnnotation4註釋");
        }
    }
}

注意事項:

  1. 是判斷某個java檔案是否存在某種型別的註釋,所以獲取的是該java檔案的類,而不是該註釋的類
  2. 獲取到後就需要進行判斷是否存在該註釋,使用isAnnotationPresent()方法

通過反射獲取註解物件的值

自定義註解:

package Day19註解;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation5 {
    String name();
    String id();
}

測試:

package Day19註解;

//獲取本類doSome()方法上面的註釋資訊

import java.lang.reflect.Method;

public class Test11 {

    @MyAnnotation5(name = "張三", id = "001")
    public void doSome(){}

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //獲取本類
        Class<?> t11Class = Class.forName("Day19註解.Test11");

        //獲取doSome()方法
        Method dsMethod = t11Class.getMethod("doSome");

        //判斷doSome()方法是否存在註解
        if (dsMethod.isAnnotationPresent(MyAnnotation5.class)){
            //獲取該註釋物件
            MyAnnotation5 dsMethodAnnotation = dsMethod.getAnnotation(MyAnnotation5.class);

            System.out.println("使用者的名字是:" + dsMethodAnnotation.name() + ",id是:" + dsMethodAnnotation.id());
        } else {
            System.out.println(t11Class.getSimpleName() + "的" + dsMethod.getName() + "沒有MyAnnotation5的註釋");
        }


        //對比試驗,判斷Test09類中的doSome()方法有無@MyAnnotation5註釋
        Class<?> aClass = Class.forName("Day19註解.Test09");
        Method doSome = aClass.getMethod("doSome");
        if (doSome.isAnnotationPresent(MyAnnotation5.class)){
            MyAnnotation5 annotation = doSome.getAnnotation(MyAnnotation5.class);
            System.out.println("使用者的名字是:" + annotation.name() + ",id是:" + annotation.id());

        } else {
            System.out.println(aClass.getSimpleName() + "的" + doSome.getName() + "沒有MyAnnotation5的註釋");
        }
    }
}