Java中的Annotation注解

一、初识Annotation注解

下面提到的这些注解如果你细心的话是肯定有印象的,我们就从这说起,Java5之后起默认的三个annotation类型。

  • @Override 只能用在方法之上的,用来告诉别人这一个方法是改写父类的。
  • @Deprecated 建议别人不要使用旧的API的时候用的,编译的时候会用产生警告信息,可以设定在程序里的所有的元素上。
  • @SuppressWarnings 这一个类型可以来暂时把一些警告信息消息关闭。

这些默认的注解很简单,肯定不能满足各个程序的需要,所以我们需要扩展注解。


二、定制自己的注解

首先我们要了解,自定义注解的语法。

1. @Target

表示该注解用于什么地方,可能的 ElemenetType 参数包括: ElemenetType.CONSTRUCTOR   构造器声明 ElemenetType.FIELD   域声明(包括 enum 实例) ElemenetType.LOCAL_VARIABLE   局部变量声明 ElemenetType.METHOD   方法声明 ElemenetType.PACKAGE   包声明 ElemenetType.PARAMETER   参数声明 ElemenetType.TYPE   类,接口(包括注解类型)或enum声明

2. @Retention

表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:

  • SOURCE:信息只会保留在程序源码里,源码如果经过了编译之后,Annotation的数据就会消失,并不会保留在编译好的.class文件里面。
  • ClASS:信息保留在程序源码里,同时也会保留在编译好的.class文件里面,在执行的时候,并不会把这一些信息加载到虚拟机(JVM)中去。系统默认值是CLASS。
  • RUNTIME:表示在源码、编译好的.class文件中保留信息,在执行的时候会把这一些信息加载到JVM中去的。

举一个例子,如@Override里面的Retention设为SOURCE,编译成功了就不要这一些检查的信息;@Deprecated里面的Retention设为RUNTIME,表示除了在编译时会警告我们使用了哪个被Deprecated的方法,在执行的时候也可以查出该方法是否被Deprecated。

3. @Documented

@Documented的目的就是让这一个Annotation类型的信息能够显示在javaAPI说明文档上;没有添加的话,使用javadoc生成API文档的时候就会找不到这一个类型生成的信息。

4. @Inherited

如果需要把Annotation的数据继承给子类,那么就会用到@Inherited这一个Annotation类型. 综上所述,见例子就明白了。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface VisitorRole {
    String value();
}



三、注解之Hello World

说明:

  1. 所有的Annotation继承java.lang.annotation接口。
  2. 只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型。
  3. 参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String.
  4. 如果只有一个参数成员,最好把参数名称设为”value”,后加小括号.例:上面的例子就只有一个参数成员。

定义Description类型的注解

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;
 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Description {
    String value();
}

定义Role类型的注解

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;
 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Role {
    String name();
    String privilege();
}

在Person类上使用注解

@Description("这里是neo的测试类,一个人类对象")
public class Person {
 
	@Role(
		name="admin",
		privilege="create"
	)
    public String method1()
    {
        return "Admin角色的人可以进入这个方法,执行新建操作";
    }   
 
    @Role(
    	name="operator",
    	privilege="delete,update"
    )
    public String method2()
    {
        return "Operator角色的人可以进入这个方法,执行删除更新操作";
    }   
 
}

测试代码

	public static void main(String[] args) throws Exception{
		String CLASS_NAME = "annotationtest.Person";
		Class test = Class.forName(CLASS_NAME);
		Method[] method = test.getMethods();
		boolean flag = test.isAnnotationPresent(Description.class);
		if (flag) {
			Description des = (Description) test.getAnnotation(Description.class);
			System.out.println(test.getName() + "类的描述:" + des.value());
		}
 
		Set set = new HashSet();
		for (int i = 0; i < method.length; i++) {
			boolean otherFlag = method[i].isAnnotationPresent(Role.class);
			if (otherFlag)
				set.add(method[i]);
		}
		for (Method m : set) {
			Role role = m.getAnnotation(Role.class);
			System.out.println(m.getName() + "方法的角色是:" + role.name());
			System.out.println(m.getName() + "方法的权限是:" + role.privilege());
		}
	}

四、为什么要使用Annotation?

废了这么半天劲,现在解释下为什么要使用Annotation机制。在Java5之前有一些ad hoc的注解方案,比如用transient修饰符来标识一个成员变量在序列化子系统中应被忽略。Java5之后注解开始流行起来,可以提供用来完整地描述程序所需的信息,而这些信息是无法用java来表达的。举个例子来说,在流行的一些开源框架Hibernate中,我们通常用XML文件来做配置,而所有的这些工作都可以通过在POJO类中定义注解来完成。 例如:

@Entity
@Table(name="T_MODEL_PLANE")
public class ModelPlane {
    private Long id;
    private String name;
    @Id
    @Column(name="PLANE_ID")
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    @Column(name="PLANE_NAME")
    public String getName() {
        return name;
    }

因此,注解使得我们能够以将由编译器来测试和验证的格式,存储有关程序的额外信息。注解可以用来生成描述符文件,甚至或是新的类定义,并且有助于减轻编写样板代码的负担。通过使用注解,我们可以将这些元数据保存在java源代码中,并利用annotation API为自己的注解构造处理工具,同时,注解的优点还包括:更加干净易读的代码以及编译器类型检查等。

Leave a Comment.