自定義 之 自定義註解解析

一.註解基礎回顧

@interface,使用這個關鍵字可以說明這是一個註解。

java.lang.annotation 提供了四種元註解,可以用來註解其他的註解,像Override這些註解都會用到它們,我們自定義註解的時候也會用到,四種註解如下:

@Target:說明註解用於什麼地方。

@Retention:什麼時候使用註解。

@Inherited:是否允許子類繼承該註解

@Documented:註解是否將包含在JavaDoc中

1,@Target的參數可以是

ElementType.TYPE : 類、接口或枚舉聲明

ElementType.FIELD : 字段聲明(包括枚舉常量)

ElementType.METHOD : 方法聲明

ElementType.PACKAGE : 包聲明

ElementType.CONSTRUCTOR : 構造器聲明

ElementType.ANNOTATION_TYPE : 註釋類型聲明,解釋一下,例如Target本身就是一個註解,那麼他自己的target就是ANNOTATION_TYPE,即target的target是ANNOTATION_TYPE。

這些參數類型也就是類類型可以獲取的類型(彆扭)。

2,@Retention定義註解的生命週期,可用參數爲枚舉類RetentionPolicy中的類型

RetentionPolicy.SOURC : 編譯器會放棄註解, 也就是編譯期一過,這些註解就沒有作用了。

    可以看到下面這些註解使用了SOURC ,從這些註解可以看出來,確實過了編譯期就沒什麼用了,所以一般都是提示或校驗會用到。

RetentionPolicy.CLASS : 註釋將被編譯器記錄在類文件中,但是在運行時不需要被VM保留。這是默認行爲。很少用到。

RetentionPolicy.RUNTIME : 註釋將由編譯器記錄在類文件中,並在運行時由VM保留,因此可以反射性地讀取它們,我們自定義的註解一般都需要用到他們。

二.註解的自定義及使用過程

我們先定義兩個註解,分別是ElementType.METHOD和ElementType.FIELD類型

/**
 * @author uiao
 * @Title: 自定義方法類型的註解
 * @date 2018/8/315:36
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface City {
    //默認值,如果你在方法使用了默認值,但是沒有填寫內容就會給附上這個值
    String code() default "010";

    String name() default "北京";
}
/**
 * @author uiao
 * @Title: 自定義屬性類型的註解
 * @date 2018/8/316:11
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Phone {
    String value() default "13261201263";
}

之後我們在Company這個類上使用我們自定義的Phone和City註解

/**
 * @author uiao
 * @Title: 註解的使用
 * @date 2018/8/315:46
 */
public class Company {

    @Phone(value = "12345")
    private String phone;

    private String cityName;

    private String cityCode;

    public Company(){}

    public Company(String phone, String cityName, String cityCode) {
        this.phone = phone;
        this.cityName = cityName;
        this.cityCode = cityCode;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    @City(name = "上海", code = "020")
    public String getCityCode() {
        return cityCode;
    }

    public void setCityCode(String cityCode) {
        this.cityCode = cityCode;
    }

    @Override
    public String toString() {
        return "Company{" +
                "phone='" + phone + '\'' +
                ", cityName='" + cityName + '\'' +
                ", cityCode='" + cityCode + '\'' +
                '}';
    }
}

測試使用註解

/**
 * @author uiao
 * @Title: 自定義註解測試
 * @date 2018/8/315:39
 */
public class AnnotationTest {
    private static Logger logger = Logger.getLogger(AnnotationTest.class);

    public static void main(String[] args) {
        Company company = injectAnnotationValue(Company.class);
        // 打印輸入註解後的值
        System.out.println("打印注入註解後的值 ==>>");
        System.out.println(company.toString());
    }

    public static Company injectAnnotationValue(Class<?> clazz) {
        Company company = new Company();
        // 遍歷Class裏使用的FIELD類型的註解

        for (Field field : clazz.getDeclaredFields()) {
            Phone phone = field.getAnnotation(Phone.class);
            if (phone != null) {
                System.out.println(clazz.getName() + "上使用了屬性註解:" + field.getName() + ",註解的值爲: " + phone.value());
                // 給company實例賦上註解的值
                company.setPhone(phone.value());
            }
        }
        // 遍歷Class裏使用的METHOD類型的註解
        for (Method method : clazz.getDeclaredMethods()) {
            City city = method.getAnnotation(City.class);
            if (city != null) {
                System.out.println(clazz.getName() + "上使用了方法註解:" + method.getName() + ",註解的值爲: "
                        + " code: " + city.code()
                        + ", name: " + city.name());
                // 給company實例賦上註解的值
                company.setCityCode(city.code());
                company.setCityName(city.name());
            }
        }
        return company;
    }
}

打印結果

D:\Java\jdk1.8.0_111\bin\java ...
annotation.Company上使用了屬性註解:phone,註解的值爲: 12345
annotation.Company上使用了方法註解:getCityCode,註解的值爲:  code: 020, name: 上海
打印注入註解後的值 ==>>
Company{phone='12345', cityName='上海', cityCode='020'}

  打印結果中可以看到我們將對象company的phone,cityCode,cityName的值都設置成了註解裏的內容。

  注意:註解類型必須要用在該用的地方,就是你自定義的註解類型是method,你就不可以在field上使用它,但是。。。我們最後是通過反射來做一些操作的,所以即使你只是在一個field上使用了一個註解,但是在使用反射獲取到註解後,可以隨意更改對象的所有field。

  說白了註解只是給我們的類,屬性或方法加打了個標籤,java支持通過反射機制獲取這個標籤。至於獲取了標籤後我們可以做什麼事情,就是自己說了算了,這也是多數框架只是改個註解就會起到很大作用的原因。

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