01-元注解
定义:可以加在注解上的注解
@Document用于制作文档;
@Target描述注解的作用范围,即限制注解可以加在什么位置,例如加在属性、方法、包上等;
TYPE,只能在类、接口和枚举类型上使用
FIELD,只能在属性上使用
METHOD,只能在方法上使用
@Retention用于定义注解的保留策略;
public void classPolicy(); flags: ACC_PUBLIC Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 11: 0 RuntimeInvisibleAnnotations: 0: #11()
复制代码
RUNTIME,表示注解会保留到运行时,只有这种类型的注解才能够被反射机制读取到;通过 javap 查看 class 文件的字节码,可以发现,此种类型的注解表示为 RuntimeVisibleAnnotations :
public void runtimePolicy(); flags: ACC_PUBLIC Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 15: 0 RuntimeVisibleAnnotations: 0: #14()
复制代码
02-注解中属性的类型
定义注解时,可用的属性类型如下:
当注解中的属性只有一个,并且名为 value 时,使用注解时,可以不指定属性名,默认为 value 赋值;当注解中的属性有多个,使用注解时,不论是否为 value 赋值,都必须指定属性名,表明一一对应关系;使用注解时,若属性为一维数组,且值只有一个,则可以省略{};
03-注解与反射接口
定义注解之后,如何读取注解中的内容呢?
java.lang.reflect 包中 AnnotatedElement 接口定义了与注解相关的方法:
/** 判断是否具备特定的注解 */boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);/** 返回特定类型的注解(若有),否则 null */<T extends Annotation> T getAnnotation(Class<T> annotationClass);/** 获得所有的注解 */Annotation[] getAnnotations();/** 获得特定类型的注解 */<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass);/** 获得直接出现的注解 */default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass);/** 获得直接出现的、特定类型的注解 */<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass);Annotation[] getDeclaredAnnotations();
复制代码
java.lang.Class、java.lang.reflect.Method、java.lang.reflect.Field 等都实现了 AnnotatedElement 接口。
04-自定义注解编程
通过上面的介绍,可以发现,自定义注解编程,基本上分为三个步骤:1)使用元注解定义自定义注解;2)在编程中使用自定义注解;3)编写读取注解并处理的逻辑。
04.1-注解编程基本原理
注解定义,@interface
注解使用,@MyAnnotation
注解读取
04.2-注解编程示例
根据注解自动生成 SQL 查询语句
定义注解
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Table { String value();}
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Column { String value();}
复制代码
使用注解
@Table("student")public class StudentInfo {
@Column("STUDENT_NAME") private String name; @Column("STUDENT_AGE") private int age; @Column("STUDENT_SEX") private int sex;
// ...getter // ...setter}
复制代码
读取注解
@Testpublic void testCase1() {
StringBuilder stringBuilder = new StringBuilder();
StudentInfo studentInfo = new StudentInfo(); studentInfo.setName("张三"); studentInfo.setAge(18); studentInfo.setSex(1);
Class<?> clazz = studentInfo.getClass(); if (!clazz.isAnnotationPresent(Table.class)) { System.err.println("StudentInfo.class上不包含@Table注解"); return ; }
Table table = clazz.getAnnotation(Table.class); String tableName = table.value(); stringBuilder.append(String.format("SELECT * FROM %s WHERE 1=1", tableName));
for (Field field : clazz.getDeclaredFields()) { if (!field.isAnnotationPresent(Column.class)) { System.out.println(String.format("%s is not annotated by @Column", field.getName())); continue; } Column column = field.getAnnotation(Column.class); String columnName = column.value(); try { Method getter = clazz.getMethod(String.format("get%s", TableColumnTest.captureName(field.getName()))); Object value = getter.invoke(studentInfo);
if (value instanceof String) { stringBuilder.append(String.format(" AND %s = '%s'", columnName, value)); } else if (value instanceof Integer) { stringBuilder.append(String.format(" AND %s = %s", columnName, value)); } else { System.err.println("不支持的变量类型"); }
} catch (NoSuchMethodException nse) {
} catch (IllegalAccessException | InvocationTargetException e) {
} }
System.out.println(stringBuilder.toString());}
public static String captureName(String str) { char[] chars = str.toCharArray(); chars[0] -= 32; return String.valueOf(chars);}
复制代码
输出结果为:
SELECT * FROM student WHERE 1=1 AND STUDENT_NAME = '张三' AND STUDENT_AGE = 18 AND STUDENT_SEX = 1
[1] java注解的本质以及注解的底层实现原理
[2] Java注解处理器
历史文章
Java Core「4」java.util.concurrent 包简介
Java Core「3」volatile 关键字
Java Core「2」synchronized 关键字
Java Core「1」JUC- 线程基础
评论