[TOC]
1. 定义
注解相当于一种标记,可加载包、类、属性、方法、方法参数和局部变量上,对程序执行没有影响。编译器、程序等可通过反射获取注解,做相应的处理(如生成SQL语句等)。Java 5开始引入。Java自带的注解包括:
- @Override:实现/重写父类方法
- @SuppressWarnings:忽略编译器警告
- @SafeVarargs:参数安全注解,Java 1.7 加入
- @Deprecated:废弃注解
- @FunctionalInterface:函数式接口注解,Java 8加入
简单的栗子:
// 注解定义
public @interface TestAnnotation{}
// 注解使用
@TestAnnotation
public class Test{}
2. 元注解
可加在注解上的注解,包括@Retention、@Documented、@Target、@Inherited、@Repeatable 5 种,也可自定义元注解,只要@Target包含ElementType.ANNOTATION_TYPE。
2.1 @Retention
注解的声明周期,定义在RetentionPolicy
枚举类中,包括RetentionPolicy.SOURCE
、RetentionPolicy.CLASS
、RetentionPolicy.RUNTIME
。
- RetentionPolicy.SOURCE:只有源代码期间保留,编译器编译时丢弃
- RetentionPolicy.CLASS:保留到编译器,加载到JVM时会被丢弃
- RetentionPolicy.RUNTIME:可加载到JVM中,运行时可通过反射获取注解信息
2.1 @Documented
生成Javadoc时,包含@Documented
注解的元素
2.2 @Target
可添加注解的位置,定义在ElementType
枚举类中。
- ElementType.TYPE:class、接口(包括注解)、枚举
- ElementType.FIELD:属性
- ElementType.METHOD:方法
- ElementType.PARAMETER:参数
- ElementType.CONSTRUCTOR:构造方法
- ElementType.LOCAL_VARIABLE:局部变量
- ElementType.ANNOTATION_TYPE:注解
- ElementType.PACKAGE:包
- ElementType.TYPE_PARAMETER:用在类型参数上,如:
// 注解定义
@Target(ElementType.TYPE_PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestTypeParam {}
// 注解使用
public class AnnotationTypeParameter<@TestTypeParam T> {}
// 会报错!!!!!
@TestTypeParam
int i = 1;
- ElementType.TYPE_USE:标注各种类型,如:
// 注解定义
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestUse {}
// 注解使用
@TestUse
int i;
// 会报错!!!!!
@TestUse
i = 1;
2.3 @Inherited
父类的注解是否可被子类继承,如:
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}
@Test
public class A {}
public class B extends A {}
子类B继承了父类A的注解。
2.4 @Repeatable
Java 1.8 加入,可重复添加多个注解,如:
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface Person{
String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{}
3. 注解属性
也叫成员变量
public enum AnnotationEnum {
Enum1(1),
ENUM2(2),
;
private int id;
AnnotationEnum(int id) {
this.id = id;
}
}
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface MetaAnnotation {
// 成员变量
String value();
}
// 生命周期 SOURCE:源文件阶段 CLASS:编译器 RUNTIME:运行期
@Retention(RetentionPolicy.RUNTIME)
// 决定可添加注解的位置 见 ElementType
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface MyAnnotation {
/**
* 定义基本属性
* @return
*/
// 不设置默认值
int id();
// 设置默认值
String name() default ""; // 设置默认值
// 数组
int[] intArr() default {};
// 枚举类型
AnnotationEnum enumTest() default AnnotationEnum.Enum1;
// 注解属性
MetaAnnotation annotationValue() default @MetaAnnotation("annotationValue");
}
@MyAnnotation(id = 1, name = "test", intArr = {1, 2}, enumTest = AnnotationEnum.ENUM2, annotationValue = @MetaAnnotation("myAnnotationTest"))
public class MyAnnotationTest {
@MyAnnotation(id = 10)
public int id;
// @MyAnnotation 会报错
public int getId() {
return id;
}
public static void main(String[] args) {
// Class对象中有处理注解的两个常用方法
if (MyAnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println("MyAnnotation.toString: " + annotation);
System.out.println("int类型:" + annotation.id());
System.out.println("Sring烈性" + annotation.name());
System.out.println("int数组: " + annotation.intArr());
System.out.println("枚举类型:" + annotation.enumTest());
System.out.println("注解类型:" + annotation.annotationValue());
}
Annotation annotation1 = MyAnnotation.class.getAnnotation(MetaAnnotation.class);
System.out.println("MetaAnnotation.toString:" + annotation1);
}
}
/*
result:
int类型:1
Sring烈性test
int数组: [I@6fadae5d
枚举类型:ENUM2
注解类型:@javastudy.annotation.MetaAnnotation(value=myAnnotationTest)
MetaAnnotation.toString:null
*/
4. Class对象中和注解相关的方法
- isAnnotationPresent:判断是否是注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
- getAnnotation:获取指定注解,如果无该注解,则返回空
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
- getAnnotations:获取所有注解
public Annotation[] getAnnotations() {}
栗子见 第3章
5. 应用实例
根据Bean
生成SQL
语句:
/**
* table注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String value();
}
/**
* 字段注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String value();
}
/**
* 学生表对应的实例
*/
@Table("test_table")
public class StudentTable {
@Column("_id")
private int id;
@Column("studentName")
private String name;
@Column("sex")
private int sex;
// 未加注解,不会生成SQL语句
private String noColumnTest;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getNoColumnTest() {
return noColumnTest;
}
public void setNoColumnTest(String noColumnTest) {
this.noColumnTest = noColumnTest;
}
}
/**
* 生成SQL语句的工具类
*/
public class SqlProduct {
public static String selectSql(Object object) {
Table table = object.getClass().getAnnotation(Table.class);
// 没有table注解,则直接返回null
if (null == table) {
return null;
}
// 获取表名
String tableName = table.value();
// SQL语句
String sql = "select * from " + tableName + "where 1 =1 ";
// 获取属性名
Field[] fields = object.getClass().getDeclaredFields();
if (null == fields || 0 == fields.length) {
return sql;
}
for (Field field : fields) {
Column column = field.getAnnotation(Column.class);
if (null == column) {
continue;
}
// 获取getter方法
String fieldName = field.getName();
String getMethodStr = "get" + field.getName().substring(0, 1).toUpperCase() + fieldName.substring(1);
try {
Method getMethod = object.getClass().getMethod(getMethodStr);
Object columnVal = getMethod.invoke(object);
sql += " and " + column.value() + " = " + columnVal;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return sql;
}
}
/**
* 生成SQL
*/
public class Client {
public static void main(String[] args) {
StudentTable studentTable = new StudentTable();
studentTable.setId(1);
studentTable.setName("xiaocui");
studentTable.setSex(1);
studentTable.setNoColumnTest("test");
String sql = SqlProduct.selectSql(studentTable);
System.out.println(sql);
}
}
/*
result:
select * from test_tablewhere 1 =1 and _id = 1 and studentName = xiaocui and sex = 1
*/
网友评论