Java注解概要

什么是注解

在各种框架如Spring,Springboot中,我们经常能看到各种注解,比如@Autowired,@ControllerAdvice等等,如果我们想要深入得去了解其中得内容的话,注解是一个必须要了解的知识。

Java注解又称为标注,是Java从1.5开始支持加入源码的特殊语法元数据;Java中的类、方法、变量、参数、包都可以被注解,在java.lang.annotation.Annotation接口中有这样的一句话,用来描述注解: The common interface extended by all annotation types 所有的注解类型都继承自这个普通的接口(Annotation) 以重载@Override这样的注解为例

1.PNG 我们从左边的结构中可以看到,Override所有的方法都是继承自Annotation这样的接口,我们可以暂时这样定义Java中的注解:

一个注解准确意义上来说,只不过是一种特殊的注释而已,这种注释都是继承自Annotation接口中。

既然是注释,那么需要对这种注解进行处理,处理的方式主要有以下两种:

一种是编译期直接的扫描,一种是运行期反射。反射的事情我们待会说,而编译器的扫描指的是编译器在对 java 代码编译字节码的过程中会检测到某个类或者方法被一些注解修饰,这时它就会对于这些注解进行某些处理。

典型的就是注解 @Override,一旦编译器检测到某个方法被修饰了 @Override 注解,编译器就会检查当前方法的方法签名是否真正重写了父类的某个方法,也就是比较父类中是否具有一个同样的方法签名。

这一种情况只适用于那些编译器已经熟知的注解类,比如 JDK 内置的几个注解,而你自定义的注解,编译器是不知道你这个注解的作用的,当然也不知道该如何处理,往往只是会根据该注解的作用范围来选择是否编译进字节码文件,仅此而已。

元注解

对于Override上的注解,可能会好奇他们是用来做什么的,这些注解被称为元注解,是一种修饰注解的注解。 Java中主要有以下几个元注解:

  1. @Target:注解的作用目标,通过ElementType来进行声明,可以表示当前注解都可以放在哪些对象上,如类,属性,方法,构造器等
  2. @Retention:注解的生命周期

这里的 RetentionPolicy 依然是一个枚举类型,它有以下几个枚举值可取:

- RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件
- RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件
- RetentionPolicy.RUNTIME:永久保存,可以反射获取
复制代码
  1. @Documented:注解是否应当被包含在 JavaDoc 文档中
  2. @Inherited:是否允许子类继承该注解

Java内置三大注解

除去上述四种元注解以外,Java还为我们预定义了另外三种注解

  • @Override
  • @Deprecated
  • @SuppressWarnings

@Override注解

如上文所示,@Override的注解如下所示:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
复制代码

它没有任何的属性,所以并不能存储任何其他信息。它只能作用于方法之上,编译结束后将被丢弃。

所以你看,它就是一种典型的『标记式注解』,仅被编译器可知,编译器在对 java 文件进行编译成字节码的过程中,一旦检测到某个方法上被修饰了该注解,就会去匹对父类中是否具有一个同样方法签名的函数,如果不是,自然不能通过编译。

@Deprecated注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
复制代码

依然是一种『标记式注解』,永久存在,可以修饰所有的类型,作用是,标记当前的类或者方法或者字段等已经不再被推荐使用了,可能下一次的 JDK 版本就会删除。

当然,编译器并不会强制要求你做什么,只是告诉你 JDK 已经不再推荐使用当前的方法或者类了,建议你使用某个替代者。

@SuppressWarnings

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    /**
     * The set of warnings that are to be suppressed by the compiler in the
     * annotated element.  Duplicate names are permitted.  The second and
     * successive occurrences of a name are ignored.  The presence of
     * unrecognized warning names is <i>not</i> an error: Compilers must
     * ignore any warning names they do not recognize.  They are, however,
     * free to emit a warning if an annotation contains an unrecognized
     * warning name.
     *
     * <p> The string {@code "unchecked"} is used to suppress
     * unchecked warnings. Compiler vendors should document the
     * additional warning names they support in conjunction with this
     * annotation type. They are encouraged to cooperate to ensure
     * that the same names work across multiple compilers.
     * @return the set of warnings to be suppressed
     */
    String[] value();
}
复制代码

那注解怎么用呢

之前我们说过,注解类似于一个标签,是贴在程序代码上供另一个程序读取的,所以我们需要定义注解,使用注解,读取注解,接下来自定义一个Junit类似的组件,来尝试下注解的基本使用方法。 可以参考github以下地址,通过定义MyAfter,MyBefore注解模拟方法执行的先后顺序 github.com/TakeatEasy/…

猜你喜欢

转载自juejin.im/post/7035643643415232549