自定义Annotation以及通过反射技术获取程序元素上的Annotation注解信息

Anonotation的含义:中文翻译为"注解",实际上表示的是一种注释的语法,这种注释和代码的注释是不一样的,代码的注释如单行注释使用双斜杠"//",或多行注释使用"/*...*/"等是给程序员看的,其主要是为了增加代码的可读性,便于代码的后期维护。而Annotation主要是服务于编译器,属于一种配置信息。在本质上,Annotation提供了一种与程序元素关联任何信息或任何元数据的方式。Annotation可以像修饰符一样被使用,它可以应用于任何程序元素(如包,类型,构造方法,方法。成员变量,参数,本地变量)的声明中。这些信息被存储在Annotation的"name=value"结构对中。Annotation类型实际上是一种接口,能够通过Java反射API(应用程序接口)的方式提供对其信息的访问。

1.基本的Annotation

@Override:用在方法上,用来告诉编译器这个方法是改写父类的。

@Deprecated:标识某个程序元素(类,方法等)已经过时,不建议使用。

@SuppressWarnings:关闭编译器对程序元素(类,方法,成员变量等)的警告。

2.JDK的元Annotation

元Annotation是用于修饰其它的Annotation定义

(1)@Retention:只能用于修改一个Annotation定义,用于指定被修饰的Annotation的保存范围。

@Retention包含一个RetentionPolicy枚举类型的value成员变量用于指定Annotation的保存范围。

RetentionPolicy的值只能是如下三个:

  1. RetentionPolicy.CLASS:编译器将把Annotation记录在类文件中,但不会被加载到JVM中。如果一个Annotation声明时没有指定范围,则默认值是CLASS。
  2. RetentionPolicy.SOURCE:此Annotation类型的信息只会记录在源文件中,编译时将被编译器丢弃,及此Annotation信息不会保存在编译好的类文件中。
  3. RetentionPolicy.RUNTIME:此Annotation类型的信息将会保留在源文件,类文件中,在执行时也会加载到Java虚拟机(JVM)中,因此使用该值的时候,程序可以利用反射获取该Annotation信息

基本的Annotation的保存范围分别是:

@Override采用的是@Retention(value = RetentionPolicy.SOURCE),注解信息只能在源文件中出现。

@Deprecated采用的是@Retention(value = RetentionPolicy.RUNTIME),注解信息在执行时出现。

@SuppressWarnings采用的是@Retention(value = RetentionPolicy.SOURCE),注解信息只能在源文件中出现。

(2)@Target只能修饰一个Annotation定义,用于指定修饰的Annotation能用于修饰那些程序元素。

@Target包含一个ElementType枚举类型的value成员变量用于指定Annotation的修饰位置。

  1. ElementType.ANNOTATION_TYPE:只能修饰Annotation
  2. ElementType.FIELD:只能修饰成员变量
  3. ElementType.LOCAL_VARIABLE:只能修饰局部变量
  4. ElementType.METHOD:只能修饰方法
  5. ElementType.PACKAGE:只能修饰包
  6. ElementType.PARAMETER:只能修饰参数
  7. ElementType.TYPE:只能修饰类,接口(包括注释类型)或枚举

(3)@Documented用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档,如果定义Annotation类时使用了@Documented修饰,则所有使用该Annotation修饰的程序元素的API文档中将会包含该Annotation说明。

(4)@Inherited指定被它修饰的Annotation将具有继承性,如果某个类使用了自定义的Annotation(定义该Annotation时使用了@Inherited修饰)修饰,则其子类将自动被该自定义的Annotation修饰。

3.自定义Annotation

自定义Annotation的语法如下:

public @interface Annotation的名称{
    数据类型 变量名称();//定义的变量必须在后面加上()
}

 示例

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.CONSTRUCTOR})
public @interface MyAnnotation {

	String key();

	String value() default "";//default用于设置该变量的默认值

	boolean required() default true;

	String[] strArr() default {};
}

 使用@interface就相当于继承了Annotation接口。在程序中只要使用了@interface声明Annotation,那么此Annotation实际上就相当于继承了java.lang.annotation.Annotation接口。

根据Annotation是否包含成员变量,可以把Annotation分为如下两类:

  1. 标记Annotation:一个没有定义成员变量的Annotation类型被称为标记。这种Annotation仅利用自身的存在与否来为我们提供信息,例如@Override等Annotation。
  2. 元数据Annotation:包含成员变量的Annotation,因为它们可以接受更多的元数据,所以也被称为元数据Annotation。

4.提取Annotation信息

AnnotationElement接口是所有程序元素(如Class,Method,Constructor等)的父接口,所以程序通过反射获取某个类的AnnotationElement对象(如Class,Method,Constructor等)之后,程序就可以调用该对象的如下3个方法来访问Annotation信息。

getAnnotation(Class<T> annotationClass):返回该程序元素上存在的指定类型的注释,如果该类型的注释不存在,则返回null。

Annotation[] getAnnotations():返回该程序元素上存在的所有注释。

boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断该程序元素上是否存在指定类型的注释,如果存在则返回true,否则返回false。

注意:只有定义采用的是@Retention(value = RetentionPolicy.RUNTIME)的Annotation才能在程序运行时被反射机制取得。

示例

@MyAnnotation(key = "four", value = "3", required = false)
public class Info {
	@MyAnnotation(key = "three", value = "zs")
	private String name;

	@MyAnnotation(key = "one", value = "1", required = false)
	public Info() {

	}

	@Override
	@Deprecated
	@MyAnnotation(key = "two")
	public String toString() {
		return "hello";
	}
}
public class GetAnnotation {
	public static void main(String[] args) throws Exception {
		Class<?> cla = Class.forName("com.example.demo.annotation.domain.Info");
		System.out.println("获取类上的@MyAnnotation注释信息");
		if (cla.isAnnotationPresent(MyAnnotation.class)) {
			MyAnnotation myAnnotation = null;
			myAnnotation = cla.getAnnotation(MyAnnotation.class);
			String key = myAnnotation.key();
			String value = myAnnotation.value();
			boolean required = myAnnotation.required();
			System.out.println(key + "," + value + "," + required);
		}
		Annotation[] m0 = cla.getAnnotations();
		for (int i = 0; i < m0.length; i++) {
			System.out.println(m0[i]);
		}

		System.out.println("获取方法上的@MyAnnotation信息");
		Method toStringMethod = cla.getMethod("toString");
		System.out.println(toStringMethod);
		if (toStringMethod.isAnnotationPresent(MyAnnotation.class)) {
			MyAnnotation myAnnotation = null;
			myAnnotation = toStringMethod.getAnnotation(MyAnnotation.class);
			String key = myAnnotation.key();
			String value = myAnnotation.value();
			boolean required = myAnnotation.required();
			System.out.println(key + "," + value + "," + required);
		}
		Annotation[] m = toStringMethod.getAnnotations();
		for (int i = 0; i < m.length; i++) {
			System.out.println(m[i]);
		}

		System.out.println("获取构造器上的@MyAnnotation的信息");
		Constructor myAnnotation1 = cla.getConstructor();
		System.out.println(myAnnotation1);
		if (myAnnotation1.isAnnotationPresent(MyAnnotation.class)) {
			MyAnnotation myAnnotation = (MyAnnotation) myAnnotation1.getAnnotation(MyAnnotation.class);
			String key = myAnnotation.key();
			String value = myAnnotation.value();
			boolean required = myAnnotation.required();
			System.out.println(key + "," + value + "," + required);
		}
		Annotation[] m1 = myAnnotation1.getAnnotations();
		for (int i = 0; i < m1.length; i++) {
			System.out.println(m1[i]);
		}

		System.out.println("获取属性上的@MyAnnotation的信息");
		Field myAnnotation2 = cla.getDeclaredField("name");
		System.out.println(myAnnotation2);
		if (myAnnotation2.isAnnotationPresent(MyAnnotation.class)) {
			MyAnnotation myAnnotation = myAnnotation2.getAnnotation(MyAnnotation.class);
			String key = myAnnotation.key();
			String value = myAnnotation.value();
			boolean required = myAnnotation.required();
			System.out.println(key + "," + value + "," + required);
		}
		Annotation[] m2 = myAnnotation2.getAnnotations();
		for (int i = 0; i < m2.length; i++) {
			System.out.println(m2[i]);
		}
	}
}

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值