自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分。开发过程中,我们也时常在应用代码中会看到诸如@Override,@Deprecated这样的注解。
在使用注解之前,程序源数据只是通过java注释和javadoc,但是注解提供的功能要远远超过这些。注解不仅包含了元数据,它还可以作用于程序运行过程中、注解解释器可以通过注解决定程序的执行顺序
使用注解来以及反射来实现的数据库查询。GreenDao即是应用了这个技术
创建一个table注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value();
}
Column,用于标记元素
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
和数据库中的表格对应
@Table("user")
public class Filtter {
@Column("id")
private int id;
@Column("userName")
private String userName;
@Column("naickName")
private String naickName;
private int age;
private String city;
@Column("Email")
private String Email;
public int getId() {
return id;
}
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNaickName() {
return naickName;
}
public void setNaickName(String naickName) {
this.naickName = naickName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
用于合成查询语句的方法
private static String query(Filtter f) {
StringBuilder sb = new StringBuilder();
// 1.获取到table的名字
Class c = f.getClass();
// 2.获取到table的名字
boolean exists = c.isAnnotationPresent(Table.class);
if (!exists) {
return null;
}
Table t = (Table) c.getAnnotation(Table.class);
String tableName = t.value();
sb.append("select * from ").append(tableName).append(" where1=1 ");
// 3.历遍所有的字段
Field[] fArray = c.getDeclaredFields();
for (Field field : fArray) {
// 4.处理每个字段对应的sql
// 4.1拿到字段名
boolean fExists = field.isAnnotationPresent(Column.class);
if (!fExists) {
continue;
}
Column column = field.getAnnotation(Column.class);
String columnName = column.value();
// 4.2拿到字段的值
String filedName = field.getName();
String getMethodName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
Object fieldValue = null;
try {
Method getMethod = c.getMethod(getMethodName);
fieldValue = getMethod.invoke(f);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 4.3拼装sql
if (fieldValue == null || (fieldValue instanceof Integer && (Integer) fieldValue == 0)) {
continue;
}
sb.append(" and ").append(filedName);
if (fieldValue instanceof String) {
if (((String) fieldValue).contains(",")) {// 代表子查询
String[] values = ((String) fieldValue).split(",");
sb.append(" in(");
for (String v : values) {
sb.append("'").append(v).append("'").append(",");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")");
} else {
sb.append("=").append("\"").append(fieldValue).append("\"");
}
} else {
sb.append("=").append(fieldValue);
}
}
return sb.toString();
}
其中利用反射查找到每一个具有Column注解的进而进行查询
对其进行测试
public static void main(String[] args) {
Filtter filtter = new Filtter();
filtter.setId(2);
filtter.setUserName("jianguotang");
filtter.setNaickName("jian");
filtter.setEmail("111@qq.com,222@qq.com");//查询邮箱为任意一个
String str = query(filtter);
System.out.println(str);
}
结果
- 注解方法不能带有参数;
- 注解方法返回值类型限定为:基本类型、String、Enums、Annotation或者是这些类型的数组;
- 注解方法可以有默认值;
- 注解本身能够包含元注解,元注解被用来注解其它注解。
这里有四种类型的元注解:
1. @Documented —— 指明拥有这个注解的元素可以被javadoc此类的工具文档化。这种类型应该用于注解那些影响客户使用带注释的元素声明的类型。如果一种声明使用Documented进行注解,这种类型的注解被作为被标注的程序成员的公共API。
2. @Target——指明该类型的注解可以注解的程序元素的范围。该元注解的取值可以为TYPE,METHOD,CONSTRUCTOR,FIELD等。如果Target元注解没有出现,那么定义的注解可以应用于程序的任何元素。
3. @Inherited——指明该注解类型被自动继承。如果用户在当前类中查询这个元注解类型并且当前类的声明中不包含这个元注解类型,那么也将自动查询当前类的父类是否存在Inherited元注解,这个动作将被重复执行知道这个标注类型被找到,或者是查询到顶层的父类。
4. @Retention——指明了该Annotation被保留的时间长短。RetentionPolicy取值为SOURCE,CLASS,RUNTIME。
Java内建注解
Java提供了三种内建注解。
@Override——当我们想要复写父类中的方法时,我们需要使用该注解去告知编译器我们想要复写这个方法。这样一来当父类中的方法移除或者发生更改时编译器将提示错误信息。
@Deprecated——当我们希望编译器知道某一方法不建议使用时,我们应该使用这个注解。Java在javadoc 中推荐使用该注解,我们应该提供为什么该方法不推荐使用以及替代的方法。
@SuppressWarnings——这个仅仅是告诉编译器忽略特定的警告信息,例如在泛型中使用原生数据类型。它的保留策略是SOURCE(译者注:在源文件中有效)并且被编译器丢弃。