一.註解基礎回顧
@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支持通過反射機制獲取這個標籤。至於獲取了標籤後我們可以做什麼事情,就是自己說了算了,這也是多數框架只是改個註解就會起到很大作用的原因。