文章目录
相比较于注释:
1,注解和注释都是为代码添加额外信息
2,定义不同。注解是Java的一种数据类型,和class,接口具有同等地位
3,作用不同。注解参与编译器,编译不过会报错
4,使用位置不同。注解的使用位置有严格限制
5,注释的作用层次仅在java文件层次,后续过程都不参与。但是注解可以参与。
AM 9:20注解定义
自定义注解格式
public @interface 注解名 {
定义体
}
从形式上看,十分类似于接口定义,但它不是接口
和类,接口的地位类似,注解也是一种数据类型。
@必不可少
注解之间不能继承
AM 9:40注解使用
在这里插入代码片
1、定义年龄(18到25)\名字(最长5个字)注解: AgeBound、NameBound
//@Target元注解,注解可以作用的目标(整个类、构造方法、成员变量)
@Target({
ElementType.TYPE,ElementType.CONSTRUCTOR,ElementType.FIELD})
AM 10:40更该注解的保留级别:为运行时(才能判断生效)
//@Retention元注解,来定义我们自己定义的注解的保留级别
@Retention(RetentionPolicy.RUNTIME)
public @interface AgeBound {
// 定义2个属性值
int ageMin();
int ageMax();
}
再定义一个注解限制名字长度
//@Retention元注解,来定义我们自己定义的注解的保留级别
@Retention(RetentionPolicy.RUNTIME)
@interface NameBound {
// 定义一个最大长度
int nameLimit() default 5;
}
结果:
true
Student{age=20, name='张三'}
true
Exception in thread "main" java.lang.IllegalArgumentException: 名字不合法,长度为:8
2、写一个学生类: Student.java
类定义好了,注解定义好了,现在做一个注解处理器
3、专门用来生产student对象: StudentFactory.java
//注解的本质是一个标签:没有处理,现在通过StudentFactory这样一个注解处理器去处理
public class StudentFactory {
通过无参的构造方法,将字节码对象传给studentCls
private Class studentCls;
public StudentFactory() {
this.studentCls = Student.class;
}
//定义一个方法:专门用于获取学生对象
public Student getStudent(int age, String name) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//满足需求:2和3
// 2、age校验
judgeAge(age);
// 3、名字的校验
judgeName(name);
// 1、通过反射去实例化(返回一个学生对象)
// 获取构造函数(参数为class类型,构造函数为2参)
Constructor declaredConstructor =
studentCls.getDeclaredConstructor(int.class, String.class);
// 暴力方式(拿私有的构造方法去实例化没有权限)(忽略语法检查)
declaredConstructor.setAccessible(true);
Student student = (Student) declaredConstructor.newInstance(age, name);
return student;
}
//===========================================================================以下是被抽取的方法
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成员变量是否使用了注解
// isAnnotationPresent是判断是否使用了注解 参数是对应的注解类型的字节码文件对象
boolean annotationPresent = ageField.isAnnotationPresent(AgeBound.class);
System.out.println(annotationPresent);
if (annotationPresent) {
// 获取属性值
// getAnnotation(AgeBound.class) 获取注解实例
AgeBound ageBound = ageField.getAnnotation(AgeBound.class);
// 获取(注解中)具体的值,拿到
int ageMax = ageBound.ageMax();
int ageMin = ageBound.ageMin();
if (age < ageMin || age > ageMax) {
throw new IllegalArgumentException("年龄不合法 :" + age);
}
}
}
}
4、测试: Test.java
在这里插入代码片