Java 注解@Annotation

1.注解的由来

在引入注解之前,在不同类型的应用程序使用XML作为标准的代码配置机制,程序员们描述其代码的形式尚未标准化,每个人的做法各异:transient关键字、注释、接口等,代码和XML的解耦以及未来对这种解耦应用的维护并不低廉,这显然不是一种优雅的方式,随之而来的JDK5.0引入一种崭新的记录元数据的形式——注解被引入到Java中。 它的作用是修饰编程元素。什么是编程元素呢?例如:包、类、构造方法、方法、成员变量等。

2.什么是注解

DK5.0中的类型:1、类(class)2、接口(interface)3、枚举(enum)4、注解(Annotation) 因此,注解与其他3种类型一样,都可以定义、使用,以及包含有自己的属性、方法

注解分类

(1)标记注释:注解的内部没有属性,称作标记注解 使用方法:@注解名 使用例子:@MarkAnnotation

(2)单值注解:注解的内部只有一个属性,称作单值注解 使用方法:@注解名(属性名=属性值) 使用例子:@SingleAnnotation(value=”abc”) //也可以写成@SingleAnnotation(“abc”) *(属性名=属性值)可以简化为(属性值),但是需要满足以下两个条件: 1、该注解必须为单值注解 2、该注解的属性名必须为value

(3)多值注解:注解的内部有多个属性,称作多值注解 使用方法:@注解名(属性名1=属性值1, 属性名2=属性值2……) 使用例子:@MultipliedAnnotation(value1 = “abc”, value2 = 30……)

元注解

Java提供了一下几个元注解(下边会有介绍)

Target、Retention、Documented和Inherited

元注解的作用:

可以用于注解类(annotate Classes)

可以用于注解接口(annotate Interfaces)

可以用于注解枚举类型(annotate Enums)

因此注解同样也可以用于注解注解(annotate Annotations)

3.注解语法

3.1注解声明介绍

我们通过一个简单的例子了解下:

  @Annotation
   @Annotation1(info = "I am Annotation")

        public AnnotationMethod(){
            //代码块
        }
  
  

从代码一步步看:

01.使用“@”作为前缀声明一盒注解,向编译器说明,该元素(Annotation)是注解

02.注解后面(),标注它的属性,采用键值对的形式,如果注解只有一个元素(或者只需要指定一个元素的值,其它则使用默认值),也可以表示成: @Annotation(“I am Annotation”);如果没有元素需要被指定,则不需要括号;

03.注解用途:可以标注在Java程序的每一个元素上使用:类,域,方法,包,变量等

3.2 预定义的注解

3.2.1 @Override

目的在于标识某一个方法是否覆盖了它的父类的方法

3.2.2 @Deprecated

属于标记注解.所谓标记注解,就是在源程序中加入这个标记后,并不影响程序的编译,但有时编译器会显示一些警告信息。

用于标明已经过时的方法或类

3.2.3 @SuppressWarnnings

用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告.

deprecation:使用了不赞成使用的类或方法时的警告;
unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 
fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
path:在类路径、源文件路径等中有不存在的路径时的警告; 
serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告; 
finally:任何 finally 子句不能正常完成时的警告; 
all:关于以上所有情况的警告。

4.定义注解

4.1 注解的定义

public @interface CustomAnnotationClass

其中** @interface**说明这是一个自定义注解的定义.

4.2 定制化

定制化时,有很多其它属性可以用在自定义注解上,但是 目标(Target)和 保留策略(Retention Policy)是最重要的两个。

4.2.1 @Target

用来约束注解可以应用的地方(如方法、类或字段),其中ElementType是枚举类型

public enum ElementType {
    /**标明该注解可以用于类、接口(包括注解类型)或enum声明*/
    TYPE,

    /** 标明该注解可以用于字段(域)声明,包括enum实例 */
    FIELD,

    /** 标明该注解可以用于方法声明 */
    METHOD,

    /** 标明该注解可以用于参数声明 */
    PARAMETER,

    /** 标明注解可以用于构造函数声明 */
    CONSTRUCTOR,

    /** 标明注解可以用于局部变量声明 */
    LOCAL_VARIABLE,
/** 标明注解可以用于注解声明(应用于另一个注解上)*/
    ANNOTATION_TYPE,

    /** 标明注解可以用于包声明 */
    PACKAGE,

    /**
     * 标明注解可以用于类型参数声明(1.8新加入)
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * 类型使用声明(1.8新加入)
     * @since 1.8
     */
    TYPE_USE
}
    
  • 当注解未指定Target值时,则此注解可以用于任何元素之上
  • 设定一个值:@Target(ElementType.METHOD)
  • 设定多个值时使用{}包含并用逗号隔开

@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})

4.2.2 @Retention

用来约束注解的生命周期,分别有三个值,源码级别(source),类文件级别(class)或者运行时级别(runtime)

  • SOURCE:注解将被编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里)
  • CLASS:注解在class文件中可用,但会被VM丢弃(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中),请注意,当注解未定义Retention值时,默认值是CLASS,如Java内置注解,@Override、@Deprecated、@SuppressWarnning等
  • RUNTIME:注解信息将在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息(源码、class文件和执行的时候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。

4.2.3 注解中的细节

@Target(ElementType.TYPE) // 注解在类上
@Retention(RetentionPolicy.RUNTIME)  //保留在运行时
@interface CustmAnnotationClass {
    /**
     * Java 元注解
     * 1. 目标
     * 2. 保留策略
     */
    String  info() default "Annotation";

}

@CustmAnnotationClass(info="OOP")
public class Test {
    
}
    
  1. 注解支持以下类型:
  • 所有基本类型 (int,float,boolean,byte,double,char,long,short)
  • String
  • Class
  • enum
  • Annomation
  • 上述类型的数组形式
  1. 注解可以作为元素的类型,也就是嵌套注解
  2. 注解默认值限制

元素必须要么具有默认值,要么在使用注解时提供元素的值。

对于非基本类型的元素,无论是在源代码中声明,还是在注解接口中定义默认值,都不能以null作为值.当然我们可以定义一些特殊的值,例如空字符串或负数,表示某个元素不存在

4.2.4 注解中的继承

  • 注解不能使用关键字extends来继承某个@interface,但注解在编译后,编译器会自动继承java.lang.annotation.Annotation接口
  • @Inherited

使用了保留注解@Inherited,但这并不是真的继承,只是通过使用@Inherited,可以让子类Class对象使用getAnnotations()获取父类被@Inherited修饰的注解,换句话说:这个类将自动地把这个注解传递到所有子类中而不用在子类中声明,通常,一个类继承了父类,并不继承父类的注解。这完全和使用注解的目的一致的:提供关于被注解的代码的信息而不修改它们的行为。

所以:@Inheriated注解仅在存在继承关系的类上产生效果,在接口和实现类上并不工作。 在默认的情况下,父类的注解并不会被子类继承。如果要继承,就必须加上Inherited注解。

可以点击这里看看哦

4.2.5 其他注解属性介绍

  • @Documented 被修饰的注解会生成到javadoc中

5.注解的获取(反射)

  • 在使用反射之前必须使用import java.lang.reflect.* 来导入和反射相关的类。
  • 如果要得到某一个类或接口的注解信息,可以使用如下代码:
Annotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);

  • 如果要得到全部的注解信息可使用如下语句:
Annotation[] annotations = TestAnnotation.class.getAnnotations();

或

Annotation[] annotations = TestAnnotation.class.getDeclaredAnnotations();


getDeclaredAnnotations与getAnnotations类似,但它们不同的是getDeclaredAnnotations得到的是当前成员所有的注解,不包括继承的。而getAnnotations得到的是包括继承的所有注解。

  • 如果要得到其它成员的注解,可先得到这个成员,然后再得到相应的注解。如得到myMethod的注解。
Method method = TestAnnotation.class.getMethod("myMethod", null);

Annotation annotation = method.getAnnotation(MyAnnotation.class);

注:要想使用反射得到注解信息,这个注解必须使用

@Retention(RetentionPolicy.RUNTIME)进行注解。

  • 判断指定类型的注解是否存在于此元素
isAnnotationPresent(Class<? extends Annotation> annotationClass)

6. Java8 变化

  • @Repeatable 表示在同一个位置重复相同的注解@Repeatable(MyAnnotation.class)
  • 新增ElementType

TYPE_PARAMETER 和 TYPE_USE ,在Java8前注解只能标注在一个声明(如字段、类、方法)上,Java8后,新增的TYPE_PARAMETER可以用于标注类型参数,而TYPE_USE则可以用于标注任意类型(不包括class)。

7.自动测试机的写法

7.1自动测试机的原理:

使用Annotation来Annotate元素的实质是:每一个ElementType内部的元素都有两个方法,分别为 (注:为方便理解,以下使用的TestCase为某个特定的自定义注释)

(1)isAnnotationPresent(TestCase.class) //判断该元素是否被TestCase所注释

(2)getAnnotation(TestCase.class) //获得TestCase的类对象

7.2自动测试机的工作过程是:

(1)首先通过反射,获得被测类o中的每一个方法

(2)对每一个方法通过使用isAnnotationPresent(TestCase.class)判断其是否被TestCase所注释(注意是.class!)

(3)如果某方法method被TestCase所注释,则通过method的getAnnotation(TestCase.class)获得TestCase的类对象tc

(4)通过tc的value()方法,获得该类对象的属性value

(注:此处使用的value()方法,正是在TestCase中定义的value属性,再次理解在注释中定义的value既是属性,也是方法)

(5)调用method方法的invoke(o,value),用value对method进行测试

参考福利

官方Java注解地址:http://docs.oracle.com/javase/tutorial/java/annotations/

维基百科中关于Java注解的解释:http://en.wikipedia.org/wiki/Java_annotation

Java规范请求250:http://en.wikipedia.org/wiki/JSR_250

Oracle 注解白皮书:http://www.oracle.com/technetwork/articles/hunter-meta-096020.html

注解API:http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html

    原文作者:CaiCai
    原文地址: https://zhuanlan.zhihu.com/p/30645583
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞