版权声明:可以转载,但请备注原文链接:https://shuwoom.com/?p=529

一、What(是什么?)

注解:是元数据,可以声明在包、类、属性、方法、局部变量、方法参数等前面,用来对这些元素进行说明、注释。

例如下面的toString函数上的@Override就是一个经常用到的注解

元注解:用来注解其他的注解

@Retention

@Target

@Documented

@Inherited

二、How(如何自定义注解?)

(1)@Retention

描述注解的保留到一个阶段(有效范围)

RetentionPolicy
SOURCE 保留到源代码
CLASS 保留到Class字节码
RUNTIME 保留到运行时

 

代码演示:

注解类:

@Retention(RetentionPolicy.SOURCE) 
public @interface MyAnnotation { } @Retention(RetentionPolicy.RUNTIME) 
public @interface OtherAnnotation { }

测试:

 

public static void main(String[] args) {

@OtherAnnotation(name="wgc")
	public void test(){
		
	}
		
	AnnotationTest annotationTest = new AnnotationTest();
	if(annotationTest.getClass().isAnnotationPresent(MyAnnotation.class)){
		System.out.println("Yes1");
	} else {
		System.out.println("No1");
	}

Method method = annotationTest.getClass().getMethod("test", null);
	if(method.isAnnotationPresent(OtherAnnotation.class)){
		System.out.println("yes2");
	} else {
		System.out.println("no2");
	}

if(method.getClass().isAnnotationPresent(OtherAnnotation.class)){
		System.out.println("yes3");
	} else {
		System.out.println("no3");
	}
}

运行结果:

如果将@Retention(RetentionPolicy.SOURCE)改为:
@Retention(RetentionPolicy.CLASS)也是No。
只有改成@Retention(RetentionPolicy.RUNTIME),才返回Yes。
因为isAnnotationPresent方法是在运行阶段判断的,只有注解保留到RUNTIME阶段才能发现。

(2)@Target

说明在哪里使用该注解

ElementType
ANNOTATION_TYPE
CONSTRUCTOR
FIELD
LOCAL_VARIABLE
METHOD
PACKAGE
PARAMETER
TYPE

注解类:代码演示:

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {

}

测试类:

@MyAnnotation
public class AnnotationTest {
…………….
}

这时候,编译器就会提醒错误,注释的地方不正确。

 

要想在类外使用注释,应该改成:

@Target({ElementType.METHOD,ElementType.TYPE})

(3)注解的属性

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
	//primitive type, String, Class, annotation, enumeration
	int id();
	String name() default "null";
	int[]array();
	Color color();
	Class clazz();
	OtherAnnotation otherAnnotation();
}
@MyAnnotation(id=12,name="wgc",array={1,2,3},color=Color.RED, clazz=String.class,otherAnnotation=@OtherAnnotation(name="other"))
public class AnnotationTest {

	public static void main(String[] args) {
		
		AnnotationTest annotationTest = new AnnotationTest();
		if(annotationTest.getClass().isAnnotationPresent(MyAnnotation.class)){
			System.out.println("Yes");
			MyAnnotation myAnnotation = annotationTest.getClass().getAnnotation(MyAnnotation.class);
			
			System.out.println(myAnnotation.id());
			System.out.println(myAnnotation.array().length);
			System.out.println(myAnnotation.color());
			System.out.println(myAnnotation.clazz());
			System.out.println(myAnnotation.otherAnnotation());
			
		} else {
			System.out.println("No");
		}
	}
 }

 

三、Where(在什么地方使用?)

  • 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等
  • 跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。也是
  • 在编译时进行格式检查。如@Override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

四、反射和注解的综合实例

注解的应用结构图:

 

综合实例代码:

第一步:实现注解类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ValueBind {
	public enum FieldType{
		STRING,INT
	};
	
	FieldType type();
	String value();
	
}

第二步:编写使用注解的类

public class Student {
	private String name;
	private int age;
	private String studentID;
	public String getName() {
		return name;
	}
	
	@ValueBind(type=FieldType.STRING, value="wgc")
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	
	@ValueBind(type=FieldType.INT, value="22")
	public void setAge(int age) {
		this.age = age;
	}
	public String getStudentID() {
		return studentID;
	}
	
	@ValueBind(type=FieldType.STRING, value="12")
	public void setStudentID(String studentID) {
		this.studentID = studentID;
	}
	
	@Override
	public String toString() {
		return "(" + getName() + "," + getAge() + "," + getStudentID() + ")";
	}
}

第三步:对注解的类进行反射

public class PersistStudent {
	 public static void main(String[] args) throws Exception {
		 Object obj = Class.forName("com.shuwoom.annotation.sample.Student").newInstance();
		 Method[]methods = obj.getClass().getDeclaredMethods();
		 
		 for(Method method : methods) {
			 if(method.isAnnotationPresent(ValueBind.class)){
				 ValueBind valueBind = method.getAnnotation(ValueBind.class);
				 
				 ValueBind.FieldType type = valueBind.type();
				 String value = valueBind.value();
				 
				 if(valueBind.type() == ValueBind.FieldType.INT){
					 method.invoke(obj, Integer.parseInt(value));
				 } else if(valueBind.type() == ValueBind.FieldType.STRING){
					 method.invoke(obj, value);
				 }
			 }
		 }
		 
		 System.out.println((Student)obj);
	 }
}

输出结果:

 

 

 

 

打赏

发表评论

电子邮件地址不会被公开。