java注解

注解(annotation)又称为元数据,是一种代码级别的说明,它为我们在代码中添加信息提供了一种形式化的方法。它是与类、接口、枚举同一个级别的,在编译的时候,注解也将被编译成class文件。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。java中内置的注解有:

@Override:表示当前的方法将会覆盖超类中的方法,如果被修饰的方法在超类中并未被定义,则编译时将会出错。

@Deprecated:表示当前的方法是一个过时的方法,如果被调用的话,编译器会发出警告。

@SuppressWarning,关闭不当的编译器警告信息。

什么是元数据呢?元数据也是数据,不过它的作用是用于描述数据的,也就是说,它是对数据及信息资源的描述性信息。总的来说,元数据可以用来创建文档,跟踪代码的依赖性,执行编译时格式检查,代替已有的配置文件。根据其所用,可以分类为:

①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
总之,元数据并不影响程序代码的执行效果,它只是被用来生成其它的文件或针在运行时知道被运行代码的描述信息。或则,有人会问,对于代码信息的描述,我们可以添加注释语句啊,但是这些注释语句在类编译的过程中自动被忽略了,生成的class文件并没有这些注释信息的存在,但是如果用注解进行描述的话,这些信息也作为class文件的一部分,可以通过反射机制实现对这些信息的访问。

我们定义自己的注解吗?当然可以了,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,在这里只是作为学习总结,未提前通知该博主,望其理解。

原文地址:https://www.cnblogs.com/codeMedita/p/7405118.html