注解(annotation)又称为元数据,是一种代码级别的说明,它为我们在代码中添加信息提供了一种形式化的方法。它是与类、接口、枚举同一个级别的,在编译的时候,注解也将被编译成class文件。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。java中内置的注解有:
@Override:表示当前的方法将会覆盖超类中的方法,如果被修饰的方法在超类中并未被定义,则编译时将会出错。
@Deprecated:表示当前的方法是一个过时的方法,如果被调用的话,编译器会发出警告。
@SuppressWarning,关闭不当的编译器警告信息。
什么是元数据呢?元数据也是数据,不过它的作用是用于描述数据的,也就是说,它是对数据及信息资源的描述性信息。总的来说,元数据可以用来创建文档,跟踪代码的依赖性,执行编译时格式检查,代替已有的配置文件。根据其所用,可以分类为:
我们定义自己的注解吗?当然可以了,java内置的标准注解上面已经讲过了,此外,java还提供了四种元注解。元注解专门负责其他的注解,主要有:
@Target 用于表示该注解可以用到什么地方,可能的ElementType参数包括:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enmu实例)
LOCAL_VARIABLE:局部变量的声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明
@Retention 表示在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
SOURCE:在原文件在有效,单将被编译器忽略
CLASS:在class文件中可以用,但会被JVM忽略
RUNTIME:运行时有效,在对象中可以用,因此可以通过反射机制读取注解的信息
@Documented 将此注解包含在Javadoc中
@Inherited 允许子类继承父类中的注解
自定义注解:
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
注解格式:
public @interface 注解名 {定义体}
注解元素可以使用的类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组
注意点:
1、访问权限只能使用public 和 default两种。
2、注解元素的使用方法是名-值对的形式,如果想要使用“快捷方式”,即不给出名,只给出值,则注解中需定义了名为value的元素,并且使用该注解的时候,如果该元素是唯一需要赋值的一个元素,则无需使用名-值对的形式。下面我们自定义一个注解UseCase:
1 @Target(ElementType.METHOD)//该注解应用于方法上 2 @Retention(RetentionPolicy.RUNTIME)//该注解在运行时有效 3 public @interface UseCase{ 4 public int id(); 5 public String description() default "no description";//如果description没被赋值,默认是后面的信息 6 }
然后定义一个类,我们在该类的方法上添加我们自定义的注解:
1 public class PasswordUtils{ 2 //添加注解信息,并给注解元素传值,形式是名-值 3 @UseCase(id=32,description="password must contains at least one numeric") 4 public boolean validationPassword(String password){ 5 return (password.matches("\w*\d\w*")); 6 } 7 //description未被赋值,则默认显示“no description” 8 @UseCase(id=48) 9 public String encryptPassword(String password){ 10 return new StringBuilder(password).reverse().toString(); 11 } 12 @UseCase(id=49,description="new password can't enqual previosly used ones") 13 public boolean checkForNewPassword(List<String> prePassword,String password){ 14 return !prePassword.contains(password); 15 } 16 }
该类定义好了,使用时和正常类的使用方法一样,因为注解并不影响类的使用,它只是对类中被注解部分的信息描述。既然我们定义的注解RetentionPolicy值是runtime级别的,那么,我们就可以在运行时获取注解信息。怎么获取呢?使用反射,根据对象获取类的方法、变量等信息。以下是读取注解的例子:
1 public class my{ 2 public static void main(String[] args) throws Exception{ 3 List<Integer> usecases=new ArrayList<Integer>(); 4 Collections.addAll(usecases,32,48,49,30); 5 trackUseCases(usecases,PasswordUtils.class); 59 }80 static void trackUseCases(List<Integer> usecases,Class<?> cl){ 81 for(Method m:cl.getDeclaredMethods()){ 82 UseCase uc=m.getAnnotation(UseCase.class); 83 if(uc!=null){ 84 System.out.println("方法: "+m.getName()+" 描述信息"); 85 System.out.println(" Found use cases: "+uc.id()+" :: "+uc.description()); 86 usecases.remove(new Integer(uc.id())); 87 } 88 } 89 for(int i:usecases){ 90 System.out.println("Warning: Missing use cases- "+i); 91 } 92 } 93 }
输出内容为:
方法: validationPassword 描述信息
Found use cases: 32 :: password must contains at least one numeric
方法: checkForNewPassword 描述信息
Found use cases: 49 :: new password can't enqual previosly used ones
方法: encryptPassword 描述信息
Found use cases: 48 :: no description
Warning: Missing use cases- 30
该程序使用了两个反射方法:getDeclaredMethods()和getAnnotation(),其中getAnnotation()方法返回指定类型的注解对象,在这里就是UseCase,而geDeclaredMethods则可以根据创建好的对象获取对象所属的类中定义的方法。我们看到,encryptPassword()方法在注解时没有指定description的值,所示通过description()方法获取到的是默认值。
声明,此部分内容有参考自http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html,在这里只是作为学习总结,未提前通知该博主,望其理解。