Java 注解
前言:这篇笔记,先介绍注解,一些简单的应用,再学习注解的底层,可能不会一次写完,后续随着理解会慢慢补上
什么是注解
Java 注解是在 JDK5 时引入的新特性,注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
注解类型定义指定了一种新的类型,一种特殊的接口类型。
在关键词 interface 前加 @ 符号也就是用@interface 来区分注解的定义和普通的接口声明。
目前大部分框架(如 Spring Boot等)都通过使用注解简化了代码并提高的编码效率。
注解作用
它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释
编译检查
编译器可以利用注解来探测错误和警告信息,如 @Override、@Deprecated。
下面这样写是正常的!

加上了@Override却不正常了,因为我们这里本来就没实现重写

编写文档
软件工具可以用来利用注解信息来生成代码、Html 文档或者做其它相应处理,如 @Param、@Return、@See、@Author 用于生成 Javadoc 文档。
测试类:
public class Demo1 {
public void test01(int a, int b){
System.out.println(a+b+"");
}
}
接着使用javadoc命令来生成doc文档

代码分析
某些注解可以在程序运行的时候接受代码的提取,值得注意的是,注解不是代码本身的一部分。如Spring 2.5 开始注解配置,减少了配置。
个人理解:通过注解可以让编译器在处理代码,编译代码的时候可以改变默认的行为,这些行为可以方便我们使用和理解!

内置注解
我们在写代码的时候会经常遇到如下的注解,一起来看下!
@Override
作用:检测被该注解标注的方法是否是继承自父类(接口)的

@Deprecated
作用:该注解标注的内容,表示已过时

@SuppressWarnings
作用:抑制警告,一般传递参数"all"

元注解
元注解的作用:负责注解其他的注解
Java中定义了4个标准的meta-annotation(元注解)类型:提供对其他annotation类型作说明
@Target
作用:描述注解能够作用的位置
首先我们先看这个注解的定义

可以看到该注解中有个名为value的函数,实则该value不是函数,而是配置参数的作用,还可以看到这个注解自身也被其他注解所标记,其中我们看到了一个Target注解,如何理解呢?
其实就是一个Target的注解,自身又被一个Target所标记,那么我们就可以理解为Target注解只能标记在注解类型上面,而不能是其他类型!
其中ElementType取值:
1、ElementType.TYPE:可以作用于类上
2、ElementType.METHOD:可以作用于方法上
3、ElementType.FIELD:可以作用于成员变量上
...
不止这些取值,我们可以在继续跟到ElementType中进行观察

自己写个小例子,如下代码,就实现了注解能够作用的地方为类上面
@Target(value = ElementType.TYPE)
public @interface MyTarget {
}

可以看到我们这里设置的value值为ElementType.TYPE,那么则说明我们只能在类上面进行注解,如下所示,可以看到不会报错

那么如果我们在属性成员上进行注解呢?可以发现直接报错了

这里还需要说下@interface是特定的写法,如下所示

@Retention
作用:描述注解被保留的阶段
先看定义:

RetentionPolicy的取值:
1、@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
2、@Retention(RetentionPolicy.SOURCE):当前被描述的注解,不会保留到class字节码文件中,不会被JVM读取到
3、@Retention(RetentionPolicy.CLASS):当前被描述的注解,会保留到class字节码文件中,不会被JVM读取到(默认状态)
关系:RUNTIME > CLASS > SOURCE
上面的三种都需要在什么时候用到?
一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解。
如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解。
如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
@Documented
作用:描述注解是否被抽取到API文档中

import java.lang.annotation.Documented;
@MyAnno(name = "T")
public class Demo1 {
@MyAnno(name = "D")
public void test01(){
}
public void test02(){
}
}
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface MyAnno {
String name();
}
接着进行javadoc进行编译文档,会发现没有被注解标记的方法test02在方法介绍中没有对应的本身注解信息(这里需要注意的是@Documented是对定义的注解的注解)

@Inherited
作用:描述注解是否被子类继承
@Documented
@Inherited
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
}
@MyAnno
public class Demo1 {
public void test01(){
}
public void test02(){
}
}
class Demo2 extends Demo1{
public static void main(String[] args) {
System.out.println(Demo2.class.isAnnotationPresent(MyAnno.class));
}
}
测试代码如下,显示的结果为true,那么则可以说明Demo2的注释存在于此元素上

那么如果我们把MyAnno的注解Inherited去掉
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
}

再次运行,结果如下:

参考文章:
上面的四个元注解讲完之后,我们再回头看一下Target这个注解,我们来进行分析下其中的含义


浙公网安备 33010602011771号