一、注解(annotation)介绍
Java在JDK5中引入源代码的注解机制。
1、什么是注解?
注解为代码添加了元数据,元数据是关于数据的组织、数据域及其关系的说明信息。
更通俗的说,注解为程序元素添加了更加直观的说明,这些说明信息与程序的业务逻辑无关,并且是供特定的工具或框架使用的。
注解可以被编译器嵌入在class文件中,从而使得JVM在运行时能够检索到,因此注解可以被反射;
注解可以不直接影响代码的执行,也可以通过它改变代码的执行流程。
2、注解的目标
注解是一种接口,通过反射机制相关的API能访问注解信息。程序框架或工具中的类根据这些信息来决定如何使用程序元素或改变框架自身的行为。但是注解不会影响程序代码实的实际执行。
注解的目的在于对编译器或依托框架(Spring)说明程序的某些信息,每一个注解对应于一个实际的注解类型。
3、Java中注解的作用
- 编写文档
- 编译检查
- 项目构建说明
- 运行时指令
- 跟踪代码依赖性
4、注解的使用
@注解名称(配置参数)
当注解有多个参数时,必须声明参数名称;而且注解的配置参数的值必须是编译时的常量。
注解可以被看成一个XML元素,该元素可以有不同的预定义的属性,而属性的值是可以在声明该元素的时候自行指定的。在代码中使用注解,就相当于把一部分元素据从XML文件移到了代码之中,在一个地方管理和维护,有利于保持代码和元数据的一致性。
5、创建自定义注解
步骤:
(1)通过@interface 声明注解名称,然后在{ }中声明注解的成员属性(即参数)。
(2)使用内置的元注解标注功能并对注解的使用范围进行限制。
ps:自定义注解时会自动继承java.lang.annotation.Annotation
/*Version注解*/ public @interface Version{ double number(); //注解成员类型为double,名为number。 } /*Author注解*/ public @interface Author{ String name() default "unknown"; //注解成员类型为String,名为name。 }
值得强调的是,null不能作为默认值!
注解的使用:
@Author(name="Johny") @Version(number=1.0) publice class MyConfig{ ... }
二、元注解(Meta-Annotation)
元注解专门用来约束其它注解,有四个:
- @Target
- @Retention
- @Documented
- @Inherited
1、@Retention
功能:定义注解被保留的持续时间,即注解的生命周期。
配置参数:RetentionPolicy
public enum RetentionPolicy{
SOURCE,
CLASS,
RUNTIME,
}
某些注解仅出现在源代码中,会被编译器丢弃;还有一些会被编译在class文件中,虽然他们会被类加载器读取,但是有可能会被JVM忽略。
(编译器默认把注解信息保留在.class文件中,为编译器或工具程序运行时提供信息)
如果程序员打算设计代码分析工具,就必须让JVM读出注解信息,以便在分析程序时使用。这时就要设置元注解@Retention的RetentionPolicy为RUNTIME,然后搭配 反射机制,通过Class类的getAnnotation()方法获得指定注解,这样就可以在运行时提取出注解的信息。
2、@Target
功能:说明注解所修饰的对象的范围
配置参数:ElementType(也是枚举类型)
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE,
/** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE }
/*注解Version只能用于修饰构造方法和方法*/ @Target({ElementType.CONSTRUCTOR,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Version{ double number(); }
3、@Documented
功能:将注解的信息加入到帮助文件中,因为默认不会添加注解信息。
配置参数:没有。
使用@Documented修饰注解类型时必须同时使用@Retention,配置参数RetentionPolicy为RUNTIME。
4、@Inherited
功能:控制注解是否会影响子类,即让注解类型被继承后任然保留在子类中。
5、运行时读取注解
注解的解析完全依赖于反射机制。程序通过反射获取某个类的Class对象后,就可以调用该对象的多个方法来取得该类的注解信息。
java.lang.reflect包所提供的反射API扩充了读取运行时注解信息的能力,它新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素。
三、注解与反射的应用
1、过滤方法
注解可以修饰方法,以便指定该方法的性质或类型,从而使得方法的调用者根据该注解来过滤能够调用的方法。在这类应用中,注解起到标记作用,指示方法是否符合条件。
2、自动化测试框架
测试是程序设计不可缺少的环节,是提高代码健壮性的必要手段。
但代码测试由于要覆盖不同的代码执行逻辑和路径,往往极为复杂,因此自动化测试框架能有效提高代码测试的效率,起到事倍功半的效果。
以下实例演示了如何通过注解来实现一个简单的测试框架,从而自动化地实现单元测试。这一做法在单元测试框架JUnit中大量应用。
四、单一抽象方法注解
单一抽象方法(Single Abstract Method,SAM)注解@FunctionalInterface的作用是限制接口有且仅有一个未实现的方法,当然可以有多个已经实现的default方法,显然,它是为Lambda表达式服务的。