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
}
复制代码
读取注解
@Test
public 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- 线程基础
评论