一、注解Annotation是什么?
简单讲它的作用是为某个成员,例如类、方法或参数附加上一些元数据,而在程序中则可以通过反射操作获取到这些数据,(搞过C#的应该知道,这个是JDK5.0借鉴的.NET中的Attribute特性)。
二、Java内置的注解
JDK自带注解3个
- @Override - 检查该方法是否重载,父类或接口没有该方法时,会报编译错误。
- @Deprecated - 标记该方法已过时,如果使用该方法,会报编译警告。
- @SuppressWarnings - 忽略编译警告,其注解目标为类、字段、函数、函数入参、构造函数和函数的局部变量,建议注解声明在最接近警告发生的位置。
// 部分参数解释:
@SuppressWarnings("all") // 抑制全部类型的警告
@SuppressWarnings("unchecked") // 告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息
@SuppressWarnings("deprecation") // 如果使用了使用@Deprecated注释的方法,编译器将出现警告信息,使用这个注解将警告信息去掉
@SuppressWarnings("unchecked", "deprecation") //告诉编译器同时忽略unchecked和deprecation的警告信息
@SuppressWarnings("unused") // 抑制未使用的变量的警告
@SuppressWarnings("serial") // 抑制某类实现Serializable,但是没有定义serialVersionUID,这个需要但是不必须的字段的警告
@SuppressWarnings("rawtypes") // 抑制没有传递带有泛型的参数的警告
元注解4个(对注解的注解)
- @Retention - 生命周期
RetentionPolicy.SOURCE:当前注解编译期可见,不写入class文件
RetentionPolicy.CLASS:写入class文件,类加载运行时丢弃
RetentionPolicy.RUNTIME:永久保存,可以反射获取(常用)
- @Target - 标记注解的作用域
ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上
ElementType.FIELD:允许作用在属性字段上
ElementType.METHOD:允许作用在方法上
ElementType.PARAMETER:允许作用在方法参数上
ElementType.CONSTRUCTOR:允许作用在构造器上
ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上
ElementType.ANNOTATION_TYPE:允许作用在注解上
ElementType.PACKAGE:允许作用在包上
- @Inherited - 是否允许子类继承该注解
- @Documented - 生成JavaDoc文档时包含注解
来个实例讲解上面的注解
@Target({ElementType.FIELD}) //或@Target(value = {ElementType.FIELD}),如果注解只有一个值约定值名称为value,故此时可省略
三、第三方注解
- Spring
@Autowired
@Service
@Repository - Mybatis
@InsertProvider
@UpdateProvider
@Options
四、自定义注解
基于注解和反射实现Java ORM框架(大家都喜欢用这个举例),
废话少说上git代码:https://github.com/storyxiao/annotation-project
- 自定义表名注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
// 默认固定命名为value
String value();
}
- 自定义字段注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
// 数据表字段名
String name();
// 查询匹配条件:EQ、LIKE
String value();
}
- 创建User实体类
(1)使用@Table("user")注解,指定该类对应数据库中表名为user。
(2)使用@Column(name = "id", value = "EQ")注解,指定数据库user表id字段按照等于条件查询。
(3)使用@Column(name = "user_name", value = "LIKE")注解,指定数据库user表user_name字段按照LIKE模糊匹配。
@Table("user")
public class User {
@Column(name = "id", value = "EQ")
private int id;
@Column(name = "user_name", value = "LIKE")
private String userName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
- 构造SQL查询语句
通过getQuerySql方法获取User对象注解的表名与字段名,并使用反射获取属性值,最后拼装为SQL查询语句。
public class TestMain {
private static String getQuerySql(User user) {
StringBuilder sb = new StringBuilder();
sb.append("select * from ");
Class c = user.getClass();
if (c.isAnnotationPresent(Table.class)) {
// 获取表名
Table table = (Table) c.getAnnotation(Table.class);
String tableName = table.value();
sb.append(tableName).append(" where 1=1 ");
// 获取字段名
Field[] fields = c.getDeclaredFields();
for (Field f : fields) {
if (f.isAnnotationPresent(Column.class)) {
Column column = (Column) f.getAnnotation(Column.class);
// 得到注解:user_name 数据库中字段名
String columnName = column.name();
String columnValue = column.value();
// 得到成员变量名:userName
String filedName = f.getName();
// 构造get方法名形如:getUserName
String getMethodName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
Object filedValue = null;
try {
// 反射获取值
Method getMethod = c.getMethod(getMethodName);
filedValue = getMethod.invoke(user);
// 合成SQL,这里就不对每种数据类型做处理了
String conStr = String.format(" and %s = '%s'", columnName, filedValue);
if (f.getGenericType().toString().equals("class java.lang.String")) {
if (columnValue.toUpperCase().equals("LIKE")) {
conStr = String.format(" and %s LIKE '%s%s%s'", columnName, "%", filedValue, "%");
} else {
conStr = String.format(" and %s = '%s'", columnName, filedValue);
}
} else if (f.getGenericType().toString().equals("int")) {
conStr = String.format(" and %s = %s", columnName, filedValue);
}
//
sb.append(conStr);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// 返回构造的SQL字符串
return sb.toString();
}
public static void main(String[] args) throws ClassNotFoundException {
User user = new User();
user.setId(1);
user.setUserName("xiao");
String sql = getQuerySql(user);
System.out.println(sql);
}
}
-
运行结果