Lit it be,Lite it be,Lit it be.|

嘿咻噜啦啦

园龄:2年4个月粉丝:0关注:1

自定义注解+反射机制

@Target用来表示注解作用范围,超过这个作用范围,编译的时候就会报错。

@Target:注解的作用目标

@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包,用于记录java文件的package信息

@Retention

source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略

class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期

runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在

这3个生命周期分别对应于:Java源文件(.java文件) ---> .class文件 ---> 内存中的字节码。

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。


 

复制代码
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Length {
    int min();

    int max();

    String errorMsg();
}
复制代码

定义了一个可用于字段上的注解@Length。

 

复制代码
@Data
public class Student implements Serializable {

    private String name;
    @Length(min = 0,max = 100,errorMsg = "除非你升仙")
    private Integer age;
    private Integer score;

    @Override
    public String toString() {
        return "Student:" + '\n' +
                "name = " + this.name + '\n' +
                "age = " + this.age + '\n' +
                "score = " + this.score + '\n'
                ;
    }

}
复制代码

定义了一个学生类,把@Length用在age上。

复制代码
public class Demo01 {

public static String validate(Object object) throws IllegalAccessException {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Length.class)) {
Length length = field.getAnnotation(Length.class);
field.setAccessible(true);
Object vObject = field.get(object);
int value = ((Integer) vObject).intValue();
// int value = ((String) field.get(object)).length();
if (value < length.min() || value > length.max()) {
return length.errorMsg();
}
}
}
return null;
}
}
复制代码
  1. Class.getDeclaredFields();
    返回 Field 对象的一个数组,该数组包含此 Class 对象所表示的类或接口所声明的所有字段(包括私有成员)。
  2. field.isAnnotationPresent,这个方法实际上是让Length注解继承了Annotation类,查看filed字段是否带有Length注解
  3. field.getAnnotation,获取这个字段上所有的注解信息。
  4. field.setAcessible,将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查;实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问 ;

    由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的。

  5. field.get,获取field上的对象。
复制代码
public class Demo23 {

    public static void main(String[] args) {
        Student student = new Student();
        student.setAge(200);
        try {
            ;
            System.out.println(Demo01.validate(student));

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
复制代码

 

打印输入结果为:

 

本文作者:嘿咻噜啦啦

本文链接:https://www.cnblogs.com/shishenapr/p/17150262.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   嘿咻噜啦啦  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起