Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.
注解的定义
注解(Annotation)是Java语言中一种特殊的修饰符,它可以用于类、方法、参数、变量、构造器以及包声明中,用于为Java代码提供元数据。相对于其他修饰符如public、final等,注解并不直接影响代码的语义,但却能被某些工具软件(如编译器、框架)所读取和利用。
注解的作用
- 编译检查 - 如@Override放在方法前,如果该方法不是重写父类的方法,则编译器会发出警告。
- 代码分析 - 通过代码里标识的注解,程序可以在编译时进行一些基于注解的处理。注解信息和JAVA的反射功能在一起时会使得程序的功能更加强大。
- 编译时动态处理 - 如常见的Java框架Spring、Hibernate、JUnit等,会在编译时读取注解的信息,然后根据注解的信息进行一些其他处理。
- 生成额外的文件 - 如Javadoc工具会根据源码中的注解来生成API文档。
内置注解
Java提供了一些预定义的注解,如:
- @Override: 限定重写父类方法。
- @Deprecated: 表示某个程序元素(如方法)已经过时。
- @SuppressWarnings: 告诉编译器忽略指定的警告。
- @SafeVarargs: 抑制堆污染警告。
- @FunctionalInterface: 标记一个接口为函数式接口。
元注解:
用于注解其他注解的注解称为元注解,简单理解就是用于注解其它新定义的注解。
Java提供了以下几种元注解:
- @Target: 表明该注解可以被应用于什么地方(如方法、类、字段等)。
- @Retention: 表明该注解的生命周期(仅源代码、编译期、运行期)。
- @Documented: 表示使用该注解的元素应被Javadoc或其他工具文档化。
- @Inherited: 表示该注解可以被子类继承
注解分类
由编译器使用的注解
含义:这类注解不会被编译进入 .class 文件,在编译后它们就被编译器丢弃了。
示例:
@Override:此注解让编译器检查该方法是否正确地实现了覆写。
@SuppressWarnings:此注解告诉编译器忽略此处代码产生的警告。由工具处理 .class 文件使用的注解
含义:有些工具在加载 class 的时候,会对 class 文件做动态修改,以实现一些特殊的功能。这类注解会被编译进入 .class 文件,但在加载完成后并不会存在于内存中。这类注解主要被一些底层库使用,一般我们不需要自己处理。
示例:可以参考 lombok。在程序运行期能够读取的注解
含义:这些注解在加载后会一直存在于 JVM 中,是最常用的注解。
示例:配置了 @PostConstruct 的方法会在调用构造方法后自动被调用。这是 Java 代码通过读取该注解实现的功能,JVM 本身并不会识别该注解。
注解的基本语法
注解的声明类似于接口的声明,但是前面多了一个@符号:
1 | //定义注解 |
1 | //使用注解 |
注解的实现原理与底层机制
在Java中,注解的实现基于反射。注解本身被编译器处理为接口,其方法则对应注解的属性。当代码运行时,可以通过反射访问这些注解和它们的属性。
注解的属性值在编译时被嵌入到使用注解的类的字节码中。当运行时环境加载这个类时,注解数据成为类的一部分,可以通过Java反射API来查询。
注解的提取
结合注解和反射可以实现强大的动态处理能力。你可以在运行时查询一个类、方法或字段上的注解信息,并据此做出相应的处理。这在很多框架中被广泛应用,比如Spring和Hibernate。
例如,下面的代码演示了如何使用反射来读取方法上的注解:
1 | public class AnnotationProcessor { |
注解实际用例
注解实际使用是更加简化编码,更方便,简洁去维护一类代码。如以下使用都可以有替方法,但是用了注解后,代码看起来更加简洁,代码的耦合度也更加小。
- lombok 编译时处理构造方法、set/get 方法等
1
2
3
4
5
6
7
8import lombok.Data;
//增加lombok的@data注解,就不需要额外写set、get方法
public class Student {
private String name;
private Integer age;
} @autowire
/@resource
spring中注入对应的service
1 | //controller中注入对应的service |
数据库读写分离 @Write @read 方便
数据缓存,如Redis 缓存
Spring web 中
@RestController
@ResponseBody
自定义注解的使用
自定义一个注解,作用于service方法,用于打印出不同的方法耗时并在控制台输出。 所有demo见 Github
1. 定义注解
1 | public CustomLog { |
2. 在对应service中使用
1 | import com.technotes.annotationdemo.annotation.CustomLog; |
3.在不同方法中进行调用
1 |
|
4.访问查看结果
1 | 访问: |
1 | 访问: |