天天看點

【Java】注解Java注解

Java注解

使用注解

編譯器可以使用的注解:

  • @Override

    :讓編譯器檢查該方法是否正确地實作了覆寫
  • @Deprecated

    :告訴編譯器該方法已經被标記為“廢棄”,引用它會提示橫線 p.hello()
  • @SuppressWarnings

    :讓編譯器忽略某些警告

定義注解

注解的參數類似于無參方法,可以用

default

設定一個預設值。最常用的參數應命名為

value

元注解:可以修飾其他注解的注解

  • @Target

    :定義

    Annotation

    可以被應用于源碼的哪些位置(最常用)
    • 類或接口:

      ElementType.TYPE

    • 字段:

      ElementType.FIELD

    • 方法:

      ElementType.METHOD

    • 構造方法:

      ElementType.CONSTRUCTOR

    • 方法參數:

      ElementType.PARAMETER

    @Target({
            ElementType.METHOD,
            ElementType.FIELD
    })
    @interface Age{
        int value() default 18;
    }
               
  • @Retention

    :定義

    Annotation

    的生命周期
    • RetentionPolicy.SOURCE

      : 在編譯期就被丢掉了
    • RetentionPolicy.CLASS

      : 僅儲存在class檔案中,它們不會被加載進JVM (預設)
    • **

      RetentionPolicy.RUNTIME

      : 會被加載進JVM,并且在運作期可以被程式讀取 **

通常我們自定義的

Annotation

都是

RUNTIME

,是以務必要加上:

  • @Repeatable

    : 定義

    Annotation

    是否可重複(用的很少)

經過

@Repeatable

修飾後,在某個類型聲明處,就可以添加多個

@Report

注解

  • @Inherited

    : 定義子類是否可繼承父類定義的

    Annotation

定義

Annotation

的步驟:

  1. @interface

    定義注解
@interface Age{
}
           
  1. 添加參數、預設值

把最常用的參數定義為

value()

,推薦所有參數都盡量設定預設值。

@interface Age{
    String level() default "teenager";
    int value() default 18;
}
           
  1. 用元注解配置注解

必須設定

@Target

@Retention

@Retention

一般設定為

RUNTIME

,因為我們自定義的注解通常要求在運作期讀取。

一般情況下,不必寫

@Inherited

@Repeatable

@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Age{
    String level() default "teenager";
    int value() default 18;
}
           

處理注解

Java提供的使用反射API讀取

Annotation

的方法包括下面兩種:

  1. 判斷某個注解是否存在于

    Class

    Field

    Method

    Constructor

  • Class.isAnnotationPresent(Class)

  • Field.isAnnotationPresent(Class)

  • Method.isAnnotationPresent(Class)

  • `Constructor.isAnnotationPresent(Class)
  1. 使用反射API讀取Annotation
  • Class.getAnnotation(Class)

  • Field.getAnnotation(Class)

  • Method.getAnnotation(Class)

  • Constructor.getAnnotation(Class)

讀取

Annotation

有兩種方法:

  1. 先判斷

    Annotation

    是否存在,若存在就讀取
Class cls = People.class;
if(cls.isAnnotationPresent(Ages.class)){
    Ages ages = cls.getAnnotation(Ages.class);
    ...
}
           
  1. 直接讀取

    Annotation

    ,如果不存在就傳回

    null

Class cls = People.class;
Ages ages = cls.getAnnotation(Ages.class);
if(ages != null){
    ...
}
           

使用注解

我們來看一個

@Range

注解,我們希望用它來定義一個

String

字段的規則:字段長度滿足

@Range

的參數定義:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Range {
    int min() default 0;
    int max() default 255;
}
           

在某個JavaBean中,我們可以使用該注解:

public class Person {
    @Range(min=1, max=20)
    public String name;

    @Range(max=10)
    public String city;
}
           

但是,定義了注解,本身對程式邏輯沒有任何影響。我們必須自己編寫代碼來使用注解。這裡,我們編寫一個

Person

執行個體的檢查方法,它可以檢查

Person

執行個體的

String

字段長度是否滿足

@Range

的定義:

void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {
    // 周遊所有Field:
    for (Field field : person.getClass().getFields()) {
        // 擷取Field定義的@Range:
        Range range = field.getAnnotation(Range.class);
        // 如果@Range存在:
        if (range != null) {
            // 擷取Field的值:
            Object value = field.get(person);
            // 如果值是String:
            if (value instanceof String) {
                String s = (String) value;
                // 判斷值是否滿足@Range的min/max:
                if (s.length() < range.min() || s.length() > range.max()) {
                    throw new IllegalArgumentException("Invalid field: " + field.getName());
                }
            }
        }
    }
}
           

這樣一來,我們通過

@Range

注解,配合

check()

方法,就可以完成

Person

執行個體的檢查。注意檢查邏輯完全是我們自己編寫的,JVM不會自動給注解添加任何額外的邏輯。