Java 註解

目錄

1、簡述

2、元註解

@Target

@Retention

@Documented

@Inherited

@Repeatable

3、常用註解

4、自定義註解

5、示例

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

 

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