反射与注解
注解简介
什么是注解
Java 注解
是 JDK5.0 引入的一种注释机制。
注解是放在 Java 源码的类、方法、字段、参数前的一种特殊“注释”。
注释会被编译器直接忽略,注解则可以被编译器打包进class文件。因此,注解是一种用作标注的元数据(描述数据的数据)。
注解的作用
Java 的注解根据其生命周期可以分为三类:
- 编译型注解,编译结束后就失效了
- 字节码型注解,JVM加载字节码文件时,会去掉相应的注解
- 运行型注解,会被加载进JVM,并在运行期可以被读取
第一类注解用于命令编译器,例如:@Override
:让编译器检查该方法是否正确地实现了覆写。这类注解不会进入.class
文件。
第二类注解只被一些底层库使用。这类注解会被编译进入.class
文件,但加载结束后并不会存在于JVM中。
第三类注解是在程序运行期能够读取的注解,它们在加载后一直存在于JVM中,这也是最常用的注解。
处理注解
第一种注解,主要由编译器使用,因此我们一般只使用,不编写。
第二种注解,主要由底层工具库使用,一般我们很少用到。
只有第三种不但要使用,还需要经常编写。
因此我们只讨论如何处理运行型注解。
扫描二维码关注公众号,回复:
13471371 查看本文章
反射处理运行型注解
读取注解,需要使用反射API。
判断某个注解是否存在于Class类
、Field类
、Method类
或Constructor类
:
Class.isAnnotationPresent(Class)
Field.isAnnotationPresent(Class)
Method.isAnnotationPresent(Class)
Constructor.isAnnotationPresent(Class)
读取注解:
Class.getAnnotation(Class)
Field.getAnnotation(Class)
Method.getAnnotation(Class)
Constructor.getAnnotation(Class)
注意:注解也是一种类class
,所有的注解均继承自java.lang.annotation.Annotation
,因此可以使用反射。
注解实战
- 定义一个注解
//定义一个RUNTIME型的注解,并指明作用于字段上
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface LengthValid {
int min() default 0;
int max() default 255;
}
复制代码
- 定义一个JavaBean并使用注解
class UserLoginInfo {
@LengthValid(min = 5, max = 10)
private final String username;
@LengthValid(min = 5, max = 20)
private final String password;
public UserLoginInfo(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
复制代码
- 编写代码来使用注解。
public class Main {
public static void main(String[] args) throws InterruptedException {
// 模拟数据
var userLoginInfos =
List.of(new UserLoginInfo("abc", "12345"),
new UserLoginInfo("abc12", "1234"),
new UserLoginInfo("abc123", "123456"));
for (var info : userLoginInfos) {
checkInfo(info);
}
}
private static void checkInfo(UserLoginInfo info) {
// 遍历所有字段
for (var field : info.getClass().getDeclaredFields()) {
// 设置private字段可访问
field.setAccessible(true);
// 通过反射获取字段上的注解
LengthValid lengthValid = field.getAnnotation(LengthValid.class);
// 如果字段上没有此注解则退出
if (lengthValid == null) return;
try {
//获取info对象此字段的值
Object o = field.get(info);
if (o instanceof String) {
String s = (String) o;
System.out.print(field.getName());
// 进行相应的逻辑判断
if (s.length() >= lengthValid.min() && s.length() <= lengthValid.max())
System.out.println("验证成功");
else
System.out.println("验证失败");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
复制代码
输出结果:
username验证失败
password验证成功
username验证成功
password验证失败
username验证成功
password验证成功