java註解從入門到入土

java註解

理解java註解

​ 註解是java提供的一種對元重新中元素關聯信息和元數據的途徑和方法。

​ Annatation(註解)是一個接口,重新可以通過反射來獲取指定程序中元素的Annatation對象,然後通過該對象來獲取註解中的元數據信息

基本語法

聲明註解與元註解

示例:

// 聲明 Test註解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{
    
}

​ 我們使用了@interface聲明瞭Test註解,並使用@Target註解傳入ElementType.METHOD參數來標明。@Test只能用於方法上,@Retention(RetentionPolicy.RUNTIME)則用來表示該註解的生存期是運行時。

​ 從代碼上看註解的定義很想接口的定義,畢竟在編譯後也會生成Test.class文件。對於@Targer和@Retention是由java提供的元註解(標記其他註解的註解)。

  • @Target用來約束註解可以應用的地方(如方法、類或字段),其中ElementType是枚舉類型其定義如下:表示可能的取值範圍

    public enum ElementType{
         // 標明該註解可以用於類、接口(包括註解類型)或enum聲明
        TYPE,
    
        // 標明該註解可以用於字段(域)聲明,包括enum實例 
        FIELD,
    
        // 標明該註解可以用於方法聲明 
        METHOD,
    
        // 標明該註解可以用於參數聲明 
        PARAMETER,
    
        // 標明註解可以用於構造函數聲明 
        CONSTRUCTOR,
    
        // 標明註解可以用於局部變量聲明 
        LOCAL_VARIABLE,
    
        // 標明註解可以用於註解聲明(應用於另一個註解上)
        ANNOTATION_TYPE,
    
        // 標明註解可以用於包聲明 
        PACKAGE,
    
        //標明註解可以用於類型參數聲明(1.8新加入)
        TYPE_PARAMETER,
    
        // 類型使用聲明(1.8新加入)
        TYPE_USE
    }
    

    當註解爲指定Target值時,此註解可以用於任何元素之上,多個值使用{}包含並用逗號隔開。

  • @Retention用來約束註解的生命週期

    • SOURCE:源碼級別,註解將會被編譯器丟棄,不會保留在編譯好的class文件中
    • CLASS:類文件級別,註解在class文件中可用,但是會被JVM丟棄,在執行的時候不會加載到虛擬機中。當註解未定義Retention值時,默認值是CLASS,如Java內置註解,@Override、@Deprecated、@SuppressWarnning等
    • RUNTIME:運行時級別,將在運行期(JVM)也保留,因此可用通過反射機制去讀取註解的內容。如SpringMvc中的@Controller、@Autowired、@RequestMapping等。

註解元素以及其數據類型

  • 標記註解:註解內部沒有定義其他元素,唯一作用就是標記聲明

​ 在自定義註解中,一般會包含一些元素以表示某些值,方便處理器使用。

​ 定義一個DBTable的註解,主要用於數據庫表與Bean類的映射,在其中聲明一個String類型的name元素,其默認值是空字符,但是必須注意到對應對應元素的證明用採用方法的聲明方式,同時可選擇使用default提供默認值

@Target(Element.TYPE)// 只能應用於類上
@Retention(RetentionPolicy.RUNTIME)// 保存到運行時
public @interface DBTable{
    String name() default "";
}

@DBTable使用方式

//在類上使用該註解
@DBTable(name = "MEMBER")
public class Member{
    
}

支持的數據類型:

  • 所有基本類型
  • String
  • Class
  • enum
  • Annotation
  • 上述類型的數組

注意:聲明註解元素時可以使用基本類型,但是不允許使用任何包裝類型,註解也是可以作爲元素的類型,也就是嵌套註解

編譯器對默認值的限制

  • 元素不能有不確定的值:要麼有默認值,要麼在使用註解時提供元素的值
  • 對於非基本類型的元素,無論是在源代碼中聲明,還是在註解接口中定義默認值,都不能以null作爲值
  • 所以說只能定義一些特殊的值來表示某個元素不存在

註解不支持繼承

​ 註解不支持繼承,因此不能使用關鍵字extends來繼承某個@interface,但是註解在編譯後會自動繼承java.lang.annotation.Annotation接口。

快捷方式

​ 註解中定義了名爲value的元素,並且在使用該註解時,如果該元素時唯一需要賦值的一個元素,那麼此時無需使用key=value的語法,只需要在括號內給出所需的值。

​ 可以應用於人格合法類型的元素,但是限制了元素名必須爲value。

  • 示例:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface IntegerValue{
    int value() default 0;
    String name() default "";
}
public class test {
    // 只想給value賦值
    @IntegerValue(20)
    private int age;
    // 都需要賦值是隻能使用key=value
    @IntegerValue(value=1000,name="zhonghu")
    public int money;

}

java內置註解與其他元註解

java提供的內置註解,主要有三種

  • @Override:用於標明此方法覆蓋了父類的方法

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    
  • @Deprecated:用於標明以及過時的方法或者類

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
    public @interface Deprecated {
    }
    
  • @SuppressWarnnings:用於有選擇的關閉編譯器對類、方法、成員變量、變量初始化的警告

    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
        String[] value();
    }
    

    其內部有一個String數組主要接收值如下

    • deprecation:使用了不贊成使用的類或方法時的警告;
    • unchecked:執行了未檢查的轉換時的警告,例如當使用集合時沒有用泛型 (Generics) 來指定集合保存的類型;
    • fallthrough:當 Switch 程序塊直接通往下一種情況而沒有 Break 時的警告;
    • path:在類路徑、源文件路徑等中有不存在的路徑時的警告;
    • serial:當在可序列化的類上缺少 serialVersionUID 定義時的警告;
    • finally:任何 finally 子句不能正常完成時的警告;
    • all:關於以上所有情況的警告。

元註解

  • @Target
  • @Retention
  • @Documented:被修飾的註解會生成到javadoc中
  • @Inherited:可以讓註解被“繼承”,只是通過使用其讓子類Class對象使用getAnnotations()獲取父類被@Inherited修飾的註解

註解與反射機制

​ java使用Annotation接口代表註解元素,該接口是所有註解類型的父接口。

​ 同時爲了運行時能準確獲取到註解的相關信息,java在java.lang.reflect反射包下新增了AnnotatedElement接口,用於表示目前正在JVM運行的程序中已使用註解的元素,通過此接口提供的方法可以利用反射技術,讀取註解的信息。

註解處理器

使用註解的過程中很重要的一部分就是創建於使用註解處理器

  • 示例:

    • 定義註解:

      import java.lang.annotation.*;
      
      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface FruitProvider{
          public int id() default -1;
          public String name() default "";
          public String address() default "";
      }
      
    • 註解使用:

      public class Apple {
          @FruitProvider(id=1,name="zhonghu",address = "china")
          private String appleProvider;
      
          public String getAppleProvider() {
              return appleProvider;
          }
      
          public void setAppleProvider(String appleProvider) {
              this.appleProvider = appleProvider;
          }
      }
      
    • 註解處理器:

      import java.lang.reflect.Field;
      
      
      public class FruitInfoUtil {
          public static void getFruitInfo(Class<?> clazz){
              String strFruitProvicer = "供應商信息:";
              Field[] fields = clazz.getDeclaredFields();//通過反射獲取處理註解
              for (Field field : fields) {
                  if (field.isAnnotationPresent(FruitProvider.class)) {
                      FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class);
                      //註解信息的處理地方
                      strFruitProvicer = " 供應商編號:" + fruitProvider.id() + " 供應商名稱:"
                              + fruitProvider.name() + " 供應商地址:"+ fruitProvider.address();
                      System.out.println(strFruitProvicer);
                  }
              }
          }
      }
      
    • 輸出

      public class FruitRun {
          public static void main(String[] args) {
              FruitInfoUtil.getFruitInfo(Apple.class);
          }
      }
      
      
  • 結果:

java8中註解增強

元註解Repeatable

​ 表示在同一位置重複相同的註解。

新增的兩種ElementType

  • TYPE_PARAMETER
    • 用於標註類型參數
  • TYPE_USE
    • 可以用於標註除class以外的任意類型
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章