关于我为啥突然想要深入的了解 Java 注解和反射
-
好奇心来啦
-
打算看源码
-
巩固 Java 基础知识(基础不牢,地动山摇)
不要说我内卷,每个人有每个人选择的路,坚持初心。
一、逻辑思维图🧐
第 1-5 小节均偏向于理论知识,若只是想要了解如何自定义注解和如何应用注解,请跳转至第 6 小节开始阅读。
在本篇中,主要是针对注解的概念
及运行时注解
进行解释说明,附带有三个实战的案例,尽可能的让大家能够理解透彻并且能够加以应用。
二、什么是注解👨🏫
Java
注解(Annotation
)用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java
注解是从 Java5 开始添加到 Java 的。--官方文档
2.1、注解
Annotion
(注解)是一个接口,程序可以通过反射来获取指定程序元素的Annotion
对象,然后通过Annotion
对象来获取注解里面的元数据。
我们常常使用的注解,@Data、@Controller
等等,这些都是注解,创建一个注解,也很简单,创建一个类,然后将class
改为 @interface
就是一个注解啦。
2.2、注解出现的位置
Java
代码中的包、类型、构造方法、方法、成员变量、参数、本地变量的声明
都可以用注解来修饰。注解本质上可以看作是一种特殊的标记,程序在编译
或者运行时
可以检测到这些标记而进行一些特殊的处理。
2.3、关于注解的处理
我们一般将利用反射来处理注解的方式称之为运行时注解
。
另外一种则是编译时注解,如我们常常使用的 lombok 里的注解,@Data
,它能够帮我们省略set/get
方法,我们在Class
上加上这个注解后,在编译的时候,lombok
其实是修改了.class
文件的,将set/get
方法放进去了,不然的话,你可以看看编译完后的.class
文件。诸如这种,我们常称为编译时注解
,也就是使用javac
处理注解。
--图:来自于极客学院
这幅图就是从.java
文件到class
文件的,再到class
文件被 JVM 加载的过程。
而其中的注解抽象语法树
这一阶段,就是去解析注解,然后根据定义的注解处理器进行相关的逻辑处理。
这一块不是我的关注点,略过略过啦,朋友们,好奇可以去研究研究噢
3、注解的目的或作用💞
-
生成文档。这是最常见的,也是 Java 最早提供的注解。如
@param、@return
等等 -
**跟踪代码依赖性,实现替代配置文件功能。**作用就是减少配置,如
Spring
中Bean
的装载注入,而且现在的框架基本上都是使用注解来减少配置文件的数量,同时这样也使得编程更加简洁,代码更加清晰。 -
在编译时进行格式检查。如
@Override
放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出; -
标识作用。当
Java
编译时或运行时,检测到这里的注解,做什么的处理,自定义注解一般如此。 -
携带信息。 注解的成员提供了程序元素的关联信息,
Annotation
的成员在Annotation
类型中以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。在此有一个特定的默认 语法:允许声明任何Annotation
成员的默认值。一个Annotation
可以将name=value
对作为没有定义默认值的Annotation
成员的值,当然也可以使用name=value
对来覆盖其它成员默认值。这一点有些近似类的继承特性,父类的构造函数可以作为子类的默认构造函数,但是也 可以被子类覆盖。 -
这么一大段话,其实就是关于注解中成员的解释。
说了这么多,其实一句话也能表达完。
注解就是一张便利贴,它贴在那里,你看到的那一刻,就明白该做什么事啦。
如出门前,门上贴着一张便利贴📌,上面写着"出门记得带钥匙",当你看到的那一刻,你就会去检查一下自己是否带钥匙啦。
在 Java 中也是一样的,你定义了一个注解,注解上可以写一些东西,然后你再将它贴在某个上面,说明白执行规则,当编译到这里的时候需要干嘛干嘛,又或者是当运行到这里的时候需要干嘛干嘛。
因为注解写的东西的不同,或者是处理注解的规则不同,而产生了不同的注解及作用。
4、JDK 内置注解💫
Java 中 内置的注解有 5 类,具体包括:
@Deprecated
:过时注解,用于标记已过时 & 被抛弃的元素(类、方法等)
@Override
:复写注解,用于标记该方法需要被子类复写
@SuppressWarnings
:阻止警告注解,用于标记的元素会阻止编译器发出警告提醒
@SafeVarargs
:参数安全类型注解,用于提醒开发者不要用参数做不安全的操作 & 阻止编译器产生 unchecked 警告,Java 1.7 后引入
5、元注解 🎯
何为元注解?就是注解的注解,就是给你自己定义的注解添加注解,你自己定义了一个注解,但你想要你的注解有什么样的功能,此时就需要用元注解对你的注解进行说明了。
接着上一个比喻
注解有很多很多吗,门上贴一个,冰箱上贴一个,书桌上贴一个等等
元注解勒就是把他们整合起来称呼的,像上面这些可以统称为生活类注解啊。所以也就是注解的注解。
5.1、@Target
在 @Target 注解中指定的每一个 ElementType 就是一个约束,它告诉编译器,这 个自定义的注解只能用于指定的类型。
说明了注解所修饰的对象范围:注解可被用于 packages、types(类、接口、枚举、Annotation 类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch 参数)。
5.2、@Retention
定义了该注解的生命周期:
-
某些注解仅出现在源代码中,而被编译器丢弃; (源码级)
-
而另一些却被编译在 class 文件中; (字节码级)
-
编译在 class 文件中的注解可能会被虚拟机忽略,而另一些在 class 被装载时将被读取(请注意并不影响 class 的执行,因为注解与 class 在使用上是被分离的)。绝大多数开发者都是使用 RUNTIME,因为我们期望在程序运行时,能够获取到这些注解,并干点有意思的事儿,而只有 RetentionPolicy.RUNTIME,能确保自定义的注解在运行时依然可见。(运行级)
使用这个元注解可以对自定义注解的“生命周期”进行限制。
RetentionPolicy.SOURCE 一般开发者很少用到,大都是 Java 内置的注解。如@Override
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUC