1. 注解概述

注解是什么:

  • 从 JDK 5.0 开始,Java 增加了对元数据(MetaData)的支持,也就是注解(Annotation)
  • 注解其实就是代码中的 特殊标记 ,这些标记可以在编译、类加载、运行时被 JVM 读取,并执行相应的处理。通过使用注解,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者部署。
  • 注解可以像修饰符一样被使用,可用于 修饰包、类、构造器、方法、成员变量、参数、局部变量声明 等,这些信息被保存在 Annotation 的 “name = value”键值对中。

注解的重要性:

  • 在 JavaEE / Android 开发中,注解占据了非常重要的角色,例如用来配置应用程序的任何切面,代替 JavaEE 旧版中所遗留的繁冗代码和 XML 配置
  • 未来的开发模式都是基于注解的,JPA 是基于注解的,Spring2.5以上 都是基于注解的。注解是一种趋势,一定程度上可以说:框架 = 注解 + 反射 + 设计模式

2. 常见注解示例

image.png
image.png
image.png
image.png


3. 内置的3个基本注解

  • @Override:限定重写父类方法,该注解只能用于方法
    • 当在子类的某一个方法前加上@Override,就等于告诉 JVM 这个方法是重写父类的,因此在编译阶段就会进行校验这个方法是不是重写方法。如果不是,编译就会报错。

image.png
image.png

  • @Deprecated:用于表示所修饰的元素(类、方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
    • 比如,当 JDK 版本更新时,新版本会向下兼容旧版本。意思时,新版本会提供一些能够代替旧版一些结构的新结构,那些旧结构虽然不用了,但是仍然可以用,没有任何问题。

image.png

  • @SuppressWarnings:抑制编译器警告

image.png
a、b 都没有被用过,所以会报灰,@SuppressWarnings(“unused”)会抑制编译器的这个操作,所以b就亮了。


4. 自定义注解

在interface前加@就行,参考SuppressWarnings源码:

  1. public @interface SuppressWarnings {
  2. /**
  3. * The set of warnings that are to be suppressed by the compiler in the
  4. * annotated element. Duplicate names are permitted. The second and
  5. * successive occurrences of a name are ignored. The presence of
  6. * unrecognized warning names is <i>not</i> an error: Compilers must
  7. * ignore any warning names they do not recognize. They are, however,
  8. * free to emit a warning if an annotation contains an unrecognized
  9. * warning name.
  10. *
  11. * <p> The string {@code "unchecked"} is used to suppress
  12. * unchecked warnings. Compiler vendors should document the
  13. * additional warning names they support in conjunction with this
  14. * annotation type. They are encouraged to cooperate to ensure
  15. * that the same names work across multiple compilers.
  16. * @return the set of warnings to be suppressed
  17. */
  18. String[] value();
  19. }

image.png
自定义注解举例:

  1. package pkg11;
  2. public @interface MyAnnotation {
  3. String value() default "123" ; // default 代表默认值
  4. }
  1. 自定义注解的使用: <br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2643809/1626702844061-19d54b7f-155b-47f5-ae09-41aa1f98723a.png#clientId=u429af510-8e2a-4&from=paste&height=186&id=u75ea765b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=186&originWidth=671&originalType=binary&ratio=1&size=13780&status=done&style=none&taskId=u39fbe4cf-c9c7-4884-833a-c137d4152ba&width=671)<br />当然这个注解没有任何用。<br />【**总结】**
  • 注解声明为: @interface
  • 内部定义成员,通常使用 value 表示。
  • 成员的形式均为无参方法。
  • 可以指定成员的默认值,使用 default 定义。
  • 如果自定义注解没有成员,表明是一个标识作用。
  • 如果注解有成员且没有默认值,则在使用时需要指明成员的值。
  • 自定义注解必须配上注解的信息处理流程(使用反射)才有意义,这点在学反射时会细说。

5. JDK 的4个元注解

所谓元注解,就是对现有注解进行修饰的注解。JDK5.0 提供了4个标准的元注解(meta-annotation)类型,分别是:

  • Retention
  • Target
  • Document
  • Inherited

比如,打开 @Override 发现该注解上面还有两个注解,这两个注解就是用来对现有注解 @Override 进行修饰的元注解:
image.png

Retention:用来指明现有注解的生命周期。
image.png
RetentionPolicy 类型源码:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

可以看到,@Override的 Retention 中的成员是 Source,说明该注释在编译成 class 文件时就会被舍弃,@SuppressWarnings 也是这样的,这是因为这些注解在运行时并不需要。但是,对于那些运行时需要调用的注解,Retention 的成员就必须要时 RUNTIME,只有这样才能在运行时通过反射来调用该注释。

Target:用于指定被修饰的 Annotation 能用于修饰哪些元素
image.png
其中,value 是一个数组,它的元素类型为 ElementType,源码为:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation interface
     * can be applied to.
     * @return an array of the kinds of elements an annotation interface
     * can be applied to
     */
    ElementType[] value();
}
 点开 SuppressWarnings,发现其 @Target 的 value 数组七个值全有,如下图所示。说明 @SuppressWarnings 可以修饰 构造器、域、局部变量、方法、包、参数、类、接口、enum声明。<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2643809/1626704737511-95e8e374-9ea7-4242-83c2-a8233965af9f.png#clientId=uc3f23f47-3402-4&from=paste&height=73&id=ubc23f728&margin=%5Bobject%20Object%5D&name=image.png&originHeight=73&originWidth=718&originalType=binary&ratio=1&size=16116&status=done&style=none&taskId=u3e0c637d-0e2e-4042-9a24-5dfc0dea8e6&width=718)<br />如果一个现有注解没有 指定 Target,则默认可以修饰任何结构,等价于 Target 成员七个值全由,如前文自定义的 MyAnnotation,其可以修饰任何结构:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2643809/1626705065054-a95edf88-eeb2-4540-a031-1666bb6dfc3f.png#clientId=uc3f23f47-3402-4&from=paste&height=316&id=u8e49256c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=316&originWidth=681&originalType=binary&ratio=1&size=33048&status=done&style=none&taskId=u3738f494-8aaf-419f-b7a6-5b215dd6c08&width=681)<br />一般而言,自定义注解时都会用到** @Retention **和 **@Target**

@Documented@Inherited : 这两个基本不会用到,了解下就行
image.png


6. JDK8 的新特性

6.1 可重复注解

首先,自定义一个注解名叫 MyAnnotations,其成员是一个现有注解的数组,如 MyAnnotation[];
MyAnnotation:

package pkg11;

public @interface MyAnnotation {
    String value() default  "123" ; // default 代表默认值
}

MyAnnotations:

package pkg11;

public @interface MyAnnotations {
    MyAnnotation[] value();
}
在 Java 8 之前,必须通过在待注解结构前使用 @MyAnnotations 才能对该结构进行重复 @MyAnnotation 注解修饰,具体格式为:
@MyAnnotations({@MyAnnotation("234"),@MyAnnotation("567")})
private String name ;

image.png
但是,在 Java8 中增加了 @Repeatable 注解,用来指明一个注解是可以重复修饰一个结构的。其用法为;在自定义的注解前加上 @Repeatable(MyAnnotations.class) 注解,其中 MyAnnotations.class 是固定格式,MyAnnotations 是以 MyAnnotation 数组为成员的注解。
这样一来,@MyAnnotation注解既可以直接重复修饰一个结构:
image.png
要注解的是,如果 @Repeatable(MyAnnotations.class) 想要成功,那么 MyAnnotations 和 MyAnnotation 的@Target 和 @Retention 的成员必须满足包含关系,即MyAnnotation的修饰目标、生命周期必须大于等于MyAnnotations ,否则 @Repeatable 会直接报错。
【例1:】
MyAnnotation:
image.png
MyAnnotations:
image.png

【例2:】
MyAnnotation:
image.png
MyAnnotations:
image.png
一般都采用例2的方式,即让二者一样。

6.2 类型注解

在 Java8 中,@Target 中的 ElementType 在原有的7个成员上有加了两个成员:
image.png

  • TYPE_PARAMETER 表示该注解能写在类型变量声明语句中(如:泛型)。
  • TYPE_USE 表示该注解能写在使用类型的任何语句中。