自定义一个注解+注解处理器

实现如下需求:
定义一个Student类,包含name和age两个成员
name中包含的字符个数不得超过指定值(注解里有具体的约束条件信)
age必须在指定范围内(注解->具体的约束条件信息 )
name和age都满足条件才能创建Student对象,否则抛出异常。(该效果由注解处理器来实现)

Student类

public class Student {
    //实例化注解,表明下面的变量赋值时,要符合注解的限制条件,才能赋值
    @AgeBound(ageMin = 18, ageMax = 25)//该注解只修饰age
    private int age;
    @NameBound(nameLimit = 5)//名字长度不能超过5
    private String name;//private,防止用户随意修改成员变量值

    //private 是防止用户直接用构造方法new对象,并给成员变量赋值,导致age的范围不符合注解要求
    //让用户只能用我们设定的方法,创建对象并赋值,
    // 我们设定的方法里面有注解处理器,能分析注解,从而限制age范围
    private Student() {
    }

    private Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})//设置注解能用在什么地方
@Retention(RetentionPolicy.RUNTIME)
//把注解的存活时间改成,运行时存活
@interface AgeBound {//用来限制年龄的注解
    // 定义2个属性值
    int ageMin();//最小年龄
    int ageMax();//最大年龄
}

@Retention(RetentionPolicy.RUNTIME)
@interface NameBound {//用来限制姓名的注解
    int nameLimit();//名字长度
}

真正用来创建对象的工厂类,里面有自定义注解处理器

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class StudentFactory {

    private Class studentCls;

    public StudentFactory() {
        this.studentCls = Student.class;
    }

    public Student getStudent(int age, String name) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        // age校验
        judgeAge(age);
        // 名字的校验
        judgeName(name);

        // 由于构造方法是私有的,所以只能通过反射获取私有构造器,并把它设为可用,创建一个学生对象并返回
        // 通过反射去实例化
        // 获取构造函数
        Constructor declaredConstructor =
                studentCls.getDeclaredConstructor(int.class, String.class);
        // 暴力方式
        declaredConstructor.setAccessible(true);
        Student student = (Student) declaredConstructor.newInstance(age, name);
        return student;
    }


    //isAnnotationPresent(),getAnnotation(),只能由Class、Method、Field对象调用
    private void judgeName(String name) throws NoSuchFieldException {
        // 通过字节码文件对象获取年龄的成员变量
        Field nameField = studentCls.getDeclaredField("name");
        // 判断是否使用了注解
        boolean annotationPresent = nameField.isAnnotationPresent(NameBound.class);
        if (annotationPresent) {
            // 获取注解实例
            NameBound nameBound = nameField.getAnnotation(NameBound.class);
            // 获取具体的值
            int nameLimit = nameBound.nameLimit();
            //校验名字是否满足条件
            if (name.length() > nameLimit) {
                throw new IllegalArgumentException("名字不合法,长度为:" + name.length());
            }
        }
    }

      private void judgeAge(int age) throws NoSuchFieldException {
        Field ageField = studentCls.getDeclaredField("age");
        // 判断age成员变量是否使用了注解,参数是对应的注解类型的字节码文件对象
        boolean annotationPresent = ageField.isAnnotationPresent(AgeBound.class);
        if (annotationPresent) {
            // 获取注解实例(对象)
            AgeBound ageBound = ageField.getAnnotation(AgeBound.class);
            // 获取注解里的属性值
            int ageMax = ageBound.ageMax();
            int ageMin = ageBound.ageMin();
            if (age < ageMin || age > ageMax) {
                throw new IllegalArgumentException("年龄不合法 :" + age);
            }
        }
    }
}

主类

import java.lang.reflect.InvocationTargetException;

public class Test {
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        Student student = new StudentFactory().getStudent(20, "李四");
        System.out.println(student);
        //输入不合法的年龄,姓名长度,运行时会报错
        Student student1 = new StudentFactory().getStudent(100, "李四3333");
        System.out.println(student1);
    }
}

运行结果 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值