Java反射(四):反射与注解

反射与注解

注解简介

什么是注解

Java 注解是 JDK5.0 引入的一种注释机制。

注解是放在 Java 源码的类、方法、字段、参数前的一种特殊“注释”。

注释会被编译器直接忽略,注解则可以被编译器打包进class文件。因此,注解是一种用作标注的元数据(描述数据的数据)。

注解的作用

Java 的注解根据其生命周期可以分为三类:

  • 编译型注解,编译结束后就失效了
  • 字节码型注解,JVM加载字节码文件时,会去掉相应的注解
  • 运行型注解,会被加载进JVM,并在运行期可以被读取

第一类注解用于命令编译器,例如:@Override:让编译器检查该方法是否正确地实现了覆写。这类注解不会进入.class文件。

第二类注解只被一些底层库使用。这类注解会被编译进入.class文件,但加载结束后并不会存在于JVM中。

第三类注解是在程序运行期能够读取的注解,它们在加载后一直存在于JVM中,这也是最常用的注解。

处理注解

第一种注解,主要由编译器使用,因此我们一般只使用,不编写。

第二种注解,主要由底层工具库使用,一般我们很少用到。

只有第三种不但要使用,还需要经常编写。

因此我们只讨论如何处理运行型注解。

反射处理运行型注解

读取注解,需要使用反射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,因此可以使用反射。

注解实战

  1. 定义一个注解
//定义一个RUNTIME型的注解,并指明作用于字段上
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface LengthValid {
    int min() default 0;
    int max() default 255;
}
复制代码
  1. 定义一个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;
    }
}
复制代码
  1. 编写代码来使用注解。
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验证成功

猜你喜欢

转载自juejin.im/post/7037115079845904414