1. 注解(Annotation)概述

  • 从JDK5.0开始,Java增加了对元数据MeteDate的支持,也就是Annotation
  • Annotation其实就是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。
  • Annotation可以像修饰符一样被使用,可以用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明,这些信息被保存在Annotationname=value
  • JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。
  • 未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.X以后也是基于注解的。注解是一种趋势,一定程度上可以说:框架 = 注解 + 反射 + 设计模式

2. 常见注解的示例

2.1 生成文档相关的注解

  • @author:标明开发该模块的作者,多个作者之间可用,分隔
  • @version:标明该模块的版本
  • @see:参考转向,也就是相关主题
  • @since:从哪个版本开始增加的
  • @param:对方法中某参数的说明,如果没有参数就不能写,格式:@param 形参名 形参类型 形参说明
  • @return:对方法返回值的说明,如果方法返回值是void则不写,格式:@return 返回值类型 返回值说明
  • @exception:对方法可能抛出的异常进行说明,如果方法没有用throw显式抛出异常就不能写,格式:@exception 异常类型 异常说明
其中,@param@return@exception这三个标记都是只用于方法的,且@param@exception可以并列多个

2.2 编译时格式检查

  • @Override:限定重写父类的方法,该注解只能用于方法
  • @Deprecated:用于表示所修饰的元素已过时。通常是因为所修饰的结构危险或存在更好地选择
  • @SuppressWarnings:抑制编译器警告

2.3 跟踪代码依赖性,实现替换配置文件的功能

  • Servlet3.0提供了注解,使得不再需要在web.xml文件中进行Servlet的部署。
  • spring框架中关于“事务”的管理
  • 单元测试使用注解标识测试方法

2.4 JDK内置三个注解的使用

2.4.1 @Override

class Person {
    private String name;

    public void walk() {

    }
}

class Student extends Person {
    // 重写方法
    @Override
    public void walk() {
        super.walk();
    }
}

在编译时编译器会校验添加了@Override注解的方法是否是重写,避免编码时的拼写错误

2.4.2 @Deprecated

public class AnnotationTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.walk();
    }
}

class Person {
    private String name;

    // 标注过时方法
    @Deprecated
    public void walk() {

    }
}

标注过时后,不代表该方法不能使用,只是给出一个提示,提示开发者该方法有新的取代方式或者是危险的

IDEA中过时方法被添加划线

在IDE中,使用了过时的方法往往会自动加上中划线

2.4.3 @SuppressWarnings

@SuppressWarnings("unused")
public class AnnotationTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.walk();
    }
}

使用该注解并指定忽略那种类型的警告后,编译器则不会提示警告信息

3. 自定义注解

  1. 注解声明为@interface
  2. 自定义注解自动继承了java.lang.annotation.Annotation接口
  3. Annotation的成员变量在Annotation中定义以无参数方法的形式声明。其方法名和返回值定义了该成员的名字和类型。我们称其为配置参数。类型只能是八种基本数据类型、StringClassenumAnnotation类型以及以上类型的数组。
  4. 可以在定义Annotation的成员变量时为其指定初始值,指定成员变量的初始值可以使用default关键字
  5. 如果只有一个参数成员,建议使用参数名为value
  6. 如果定义的注解含有配置参数,那么使用时必须指定参数值,除非它有默认值。格式是参数名=参数值,如果只有一个参数成员,且名称为value,可以省略value=
  7. 没有成员定义的Annotation称为标记;包含成员变量的Annotation称为元数据Annotation
注意:自定义注解必须配上注解的信息处理流程(使用反射)才有意义
public @interface MyAnnotation {
    String value() default "hello";
}

4. Java中4个元注解的使用

  • JDK的元Annotation用于修饰其它Annotation定义
  • JDK5提供了4个标准的meta-annotation类型,分别是

    • Retention:只能用于修饰一个Annotation定义,用于指定该Annotation的生命周期,@Retention包含一个RetentionPolicy类型的成员变量,使用Retention时必须为value成员变量指定值:

      • RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的注解
      • RetentionPolicy.CLASS:在class文件中有效(即class保留),当运行Java程序时,JVM不会保留注释,这一策略是默认值
      • RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行Java程序时,JVM会保留注释,程序可以通过反射获取该注释
    • Target:用于修饰Annotation定义,用于指定被修饰的Annotation能用于修饰哪些元素。@Target也包含一个名为value的成员变量,默认为任意元素,取值有:

      • CONSTRUCTOR:用于描述构造器
      • FIELD:用于描述域
      • LOCAL_VARIABLE:用于描述局部变量
      • METHOD:用于描述方法
      • PACKAGE:用于描述包
      • PARAMETER:用于描述参数
      • TYPE:用于描述类、接口(包括注解类型)或enum声明
    • Documented:用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档。默认情况下,javadoc是不包括注解的。

      • 定义为Documented的注解必须设置Retention值为RUNTIME
    • Inherited:被它修饰的Annotation将具有继承性。如果某个类型使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解

      • 比如:如果把标有Inherited注解的自定义注解标注在类级别上,子类则可以继承父类级别的注解
      • 实际应用中使用较少
自定义注解通常都会指明RetentionTarget两个注解

5. JDK8中注解新特性

5.1 可重复注解

之前的写法是定义一个新的注解,其中value的类型时一个注解数组,通过此方法在使用时即可实现注解的重复使用:

public @interface MyAnnotation {
    String value() default "hello";
}


public @interface MyAnnotations {
    MyAnnotation[] value();
}

@MyAnnotations({@MyAnnotation, @MyAnnotation(value = "test")})
class Person {
    private String name;

    public void walk() {

    }
}

JDK8新特性的使用方式:

  1. MyAnnotation上声明@Repeatable,成员值为MyAnnotations.class
  2. MyAnnotation@Target@Retention必须和MyAnnotations的相同

5.2 类型注解

  • 在JDK8之后,关于元注解@Target的参数类型ElementType枚举值新增了两个:TYPE_PARAMETERTYPE_USE
  • 在Java8之前,注解只能是在声明的地方所用,Java8开始,注解可以应用在任何地方

    • ElementType.TYPE_PARAMETER表示该注解能写在类型变量声明的语句中(如:泛型声明)
    • ElementType.TYPE_USE表示该注解能写在使用类型的任何语句中
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface MyAnnotation {
    String value() default "hello";
}


class Generic<@MyAnnotation T> {
    public void show() throws @MyAnnotation RuntimeException{
        ArrayList<@MyAnnotation String> list = new ArrayList<>();
        int num = (@MyAnnotation  int)10L;
    }
}
最后修改:2021 年 03 月 19 日
如果觉得我的文章对你有用,请随意赞赏