目錄
1、簡述
註解(Annotation)是JDK5.0中引入的新特性。那麼什麼是註解呢?官方解釋是:註解是一系列元數據,用於解釋程序代碼,可修飾類、方法、變量等,對修飾的代碼沒有直接影響。用比較通俗的話語來說,註解就是代碼中的特殊標記,用於修飾代碼(類,方法,變量等),並且對代碼的運行效果沒有直接影響。那麼註解修飾代碼有什麼作用呢? 首先,註解可以提供信息給開發工具(編譯器)用於檢測錯誤或警告信息等;其次,在編譯期,開發工具可以通過註解信息生成html文檔或者做其他處理;最後,在運行前,可以利用反射機制獲取註解的內容。當然這幾個時期可以通過元註解設置,如果註解設置爲源碼期,則編譯和運行時期就不會有註解信息,同理註解使用時期設置的是編譯期的,則在運行期就獲取不到註解信息。註解在平時後臺開發,框架和jdk源碼中都比較常見的,理解了註解,在後續的開發或學習源碼時是特別有用的。
2、元註解
理解了註解概念,那麼什麼是元註解呢?通俗的說就是修飾註解的註解就叫做元註解,Java中的元註解有以下幾個,分別爲@Target,@Retention,@Documente,@Inherited,@Repeatable(JDK1.8引入的)。下面介紹下這幾個元註解:
@Target
描述了註解應該用於什麼地方,即使用範圍。取值在java.lang.annotation.ElementType 枚舉類中,分別爲:
- TYPE:類,接口(包括註釋類型)或枚舉聲明
- FIELD:字段聲明(包括枚舉常數)
- METHOD:方法聲明
- PARAMETER:正式參數聲明
- CONSTRUCTOR:構造函數聲明
- LOCAL_VARIABLE:局部變量聲明
- ANNOTATION_TYPE:註解類型聲明
- PACKAGE:包聲明
// 表示此註解可以修飾類,接口,方法,構造方法,不能修飾其他
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
@interface MyAnnotationOne {
}
// 表示此註解只能用於方法,不能修飾其他
@Target({ElementType.METHOD})
@interface MyAnnotationTwo {
}
@MyAnnotationOne
class Person {
@MyAnnotationTwo
public void fun() { }
}
@Retention
描述了被修飾註解使用的生命週期,註解的只取RetentionPolicy枚舉類,值如下:
- SOURCE:表示註解只存在於源碼時期,編譯的class文件中就沒有此註解了。
- CLASS:表示註解存在於編譯期。
- RUNTIME:表示註解存在於運行期,在運行期還可通過反射機制獲取註解的值。
@Retention(value=RetentionPolicy.SOURCE)
@interface MyAnnotationOne {
}
// 此處value= 可以省略
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotationTwo {
}
@Documented
這個註解說明了被修飾的註解可以被文檔化,這是一個標記註解,標記註解就是沒有成員的註解。
@Inherited
這個註解也是個標記註解,字面意思是繼承的意思,它說的是如果某個類A(非接口)被@Inherited註解修飾的註解B所修飾,則類A的子類自動繼承了註解B。
@Repeatable
這個註解是在JDK1.8引入的,是重複的意思。怎麼用呢?例如,在一個管理系統中,角色可能有管理員,教師,指導員,導師,學生等,某個人可能有其中幾個角色,我們需要通過註解的方式來實現,那麼此時就可以用@Repeatable註解,示例如下:
public class RepeatableTest {
public static void main(String[] args) {
Class<User> manClass = User.class;
boolean flag = manClass.isAnnotationPresent(UserRoles.class);
if (flag) {
UserRoles userRoles = (UserRoles) manClass.getAnnotation(UserRoles.class);
for (Role role : userRoles.value()) {
System.out.println(role.roleName());
}
}
}
}
@Repeatable(UserRoles.class)
@interface Role {
String roleName() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface UserRoles {
Role[] value();
}
@Role(roleName="admin")
@Role(roleName="tutor")
class User { }
3、常用註解
Java還提供了幾個常用的註解,有@Override,@Deprecated,@SuppressWarnings等等。
- @Override:指的是重寫,基本上在子類重寫父類方法時會使用,子類方法用了此註解,但方法名和父類不同時,IDE工具基本都會做錯誤提示的。
- @Deprecated:指的是廢棄,一般JDK源碼中非常常見,例如某個方法過時了,此時會用此註解,提示開發者,此方法過時了,不要再用了(實際上還可以用,但建議不要使用過時的方法)。
- @SuppressWarnings:指的是忽視警告,例如使用了廢棄的方法,實現了Serializable但未生成serialVersionUID,IDE工具都會做提示,此時使用此註解可以忽略警告。
4、自定義註解
有時候我們需要使用註解,但現有的註解又無法滿足要求,則可以自定義註解。自定義註解有以下幾個規則:
- 自定義註解格式爲:修飾符 @interface 註解名 { 註解體 },註解體的格式爲:修飾符 類型 成員名() default 成員默認值;
- 註解可以沒有註解體,此時註解爲標記註解,只起標記作用;成員可以沒有默認值。
- 註解和成員的修飾符只能爲public或默認訪問權限。
- 成員類型只能爲基本數據類型、數組、String、枚舉,類等數據類型,不能爲自定義數據類型。
- 獲取註解信息需要通過反射機制獲取。
5、示例
下面通過一個簡單的示例來學習下自定義註解(示例中用到了反射,不瞭解反射機制的先看下:https://blog.csdn.net/lanmuhhh2015/article/details/102462338):
package com.base.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class CustomAnnotation {
public static void main(String[] args) throws Exception {
Class<?> userClass = Class.forName("com.base.annotation.User");
// 獲取類的相關注解值
getClassAnnotationVal(userClass);
// 獲取類中方法的相關注解值
getMethodAnnotationVal(userClass);
// 獲取類中屬性的相關注解值
getFieldAnnotationVal(userClass);
}
private static void getClassAnnotationVal(Class<?> obj) {
String className = obj.getName();
// 獲取類的AuthorAnnotation註解值
boolean isHaveAnn = obj.isAnnotationPresent(AuthorAnnotation.class);
if (isHaveAnn) {
AuthorAnnotation author = obj.getAnnotation(AuthorAnnotation.class);
System.out.println(className + ":" + author.name());
}
// 獲取類的DescriptionAnnotation註解值
isHaveAnn = obj.isAnnotationPresent(DescriptionAnnotation.class);
if (isHaveAnn) {
DescriptionAnnotation des = obj.getAnnotation(DescriptionAnnotation.class);
System.out.println(className + ":" + des.value());
}
}
private static void getMethodAnnotationVal(Class<?> obj) {
Method[] methods = obj.getDeclaredMethods();
boolean flag = false;
for (Method method : methods) {
String methodName = method.getName();
flag = method.isAnnotationPresent(AuthorAnnotation.class);
if (flag) {
AuthorAnnotation ann = method.getAnnotation(AuthorAnnotation.class);
System.out.println(methodName+":"+ann.name());
}
flag = method.isAnnotationPresent(DescriptionAnnotation.class);
if (flag) {
DescriptionAnnotation des = method.getAnnotation(DescriptionAnnotation.class);
System.out.println(methodName+":"+des.value());
}
}
}
private static void getFieldAnnotationVal(Class<?> obj) {
Field[] fields = obj.getDeclaredFields();
boolean flag = false;
for (Field field : fields) {
String fieldName = field.getName();
flag = field.isAnnotationPresent(AuthorAnnotation.class);
if (flag) {
AuthorAnnotation ann = field.getAnnotation(AuthorAnnotation.class);
System.out.println(fieldName+":"+ann.name());
}
flag = field.isAnnotationPresent(DescriptionAnnotation.class);
if (flag) {
DescriptionAnnotation des = field.getAnnotation(DescriptionAnnotation.class);
System.out.println(fieldName+":"+des.value());
}
}
}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface AuthorAnnotation {
String name() default "zhangsan";
}
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface DescriptionAnnotation {
String value();
}
@AuthorAnnotation
@DescriptionAnnotation("this is a user class")
class User {
@DescriptionAnnotation("this is userName field")
private String userName;
@AuthorAnnotation(name="lisi")
@DescriptionAnnotation("this is getUserName function")
public String getUserName() {
return userName;
}
@AuthorAnnotation(name="wangwu")
@DescriptionAnnotation(value="this is setUserName function")
public void setUserName(String userName) {
this.userName = userName;
}
}
運行結果:
com.base.annotation.User:zhangsan
com.base.annotation.User:this is a user class
getUserName:lisi
getUserName:this is getUserName function
setUserName:wangwu
setUserName:this is setUserName function
userName:this is userName field