什么是注解?
注解,可以看作是对 一个 类/方法 的一个扩展的模版,每个 类/方法 按照注解类中的规则,来为 类/方法 注解不同的参数,在用到的地方可以得到不同的 类/方法 中注解的各种参数与值。从JDK5开始,Java增加了对元数据(描述数据属性的信息)的支持。其实说白就是代码里的特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署。------百度百科
注解的分类
1、按照运行机制分
- 源码注解
注解只在源码中存在,编译成.class文件就不存在了
- 编译时注解
注解在源码和.class文件中都存在,如JDK中自带的
@Override
,@Deprecated
,@SuppviseWarnings
均是编译时注解
- 运行时注解
在运行时还起作用,甚至会影响运行逻辑的注解,如Spring框架中的
@AutoWrite
注解
2、按照来源分
- 来自JDK的注解
限定父类重写方法-
@Override
:当子类重写父类方法时,子类可以加上这个注解,那这有什么什么用?这可以确保子类确实重写了父类的方法,避免出现低级错误
标示已过时-
@Deprecated
:这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类,方法时编译器会给出警告(删除线)
抑制编译器警告-
@SuppressWarnings
:被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告,例如修饰一个类,那他的字段,方法都是显示警告
“堆污染”警告-
@SafeVarargs
:把不带泛型的对象赋给一个带泛型的对象,例List list = new ArrayList();
函数式接口-
@Functionallnterface
:什么是函数式?如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),接口体内只能声明常量字段和抽象方法,并且被隐式声明为public,static,final。接口里面不能有私有的方法或变量。这个注解有什么用?这个注解保证这个接口只有一个抽象方法,注意这个只能修饰接口
- 来自第三方的注解
Spring中的
@Autowrite
- 我们自己定义的注解
自定义注解-
@MyAnnotation
自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {//@interface注解关键字
String desc();//成员以无参无异常方式声明
int age() default 18;//可以用default关键字为成员指定一个默认值
}
@interface为注解的关键字
1、成员类型是受限的,只允许原始数据类型和String、Class、Annotation、Enumeration
2、如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=)
3、注解类可以没有成员,没有成员的注解称为标识注解
1、元注解
- @Target:注解的作用范围
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
public enum ElementType {
/**
类、接口或者一个枚举类型声明
Class, interface (including annotation type), or enum declaration
*/
TYPE,
/**
字段声明(包括枚举类型)
Field declaration (includes enum constants)
*/
FIELD,
/** 方法声明 Method declaration*/
METHOD,
/** 形参声明 Formal parameter declaration*/
PARAMETER,
/** 构造函数声明 Constructor declaration*/
CONSTRUCTOR,
/** 局部变量声明 Local variable declaration*/
LOCAL_VARIABLE,
/** 注解类型声明 Annotation type declaration*/
ANNOTATION_TYPE,
/** 包声明 Package declaration*/
PACKAGE,
/**
* 表示该注解能写在类型变量的声明语句中 Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 表示该注解能写在使用类型的任何语句中 Use of a type
*
* @since 1.8
*/
TYPE_USE
}
- @Retention:注解的声明周期
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
* 只在源码显示。编译时会丢弃
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
* 编译时会记录到class中,运行时会忽略
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
* 运行时存在,可以通过反射读取
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
- @Inherited:允许制类继承
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
- @Documented:生成javadoc时会包含注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
2、使用自定义注解
例:定义一个JavaBean与数据库之间映射的注解
- 注解Table(表名)
@Target({ElementType.TYPE})//作用于类
@Retention(RetentionPolicy.RUNTIME)//运行时注解
@Documented
public @interface Table {
String value();//只有一个字段,只能为value
}
- 注解Column(字段名)
@Target({ElementType.FIELD})//作用于字段
@Retention(RetentionPolicy.RUNTIME)//运行时注解
@Documented
public @interface Column {
String value();//只有一个字段,只能为value
}
- JavaBean-User
@Table("user_table")//对应数据库中的表名
public class User {
@Column("user_id")//对应数据库中的字段名
private String id;
@Column("user_name")
private String name;
@Column("user_sex")
private String sex;
@Column("user_age")
private Integer age;
public User() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
- JavaBean-Department
@Table("department_table")//对应数据库中的表名
public class Department {
@Column("department_id")//对应数据库中的字段名
private String id;
@Column("department_name")
private String name;
@Column("department_amount")
private Integer amount;
public Department() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
}
- 生成SQL语句的方法
/**
* 获取对象的SQL语句
*
* @param obj 对象
* @return SQL语句
*/
private static String getSqlStatement(Object obj) {
StringBuilder sb = new StringBuilder();
//1、获取对象的class
Class clazz = obj.getClass();
//2、获取表名
boolean isExists = clazz.isAnnotationPresent(Table.class);
if (!isExists) {
return null;
}
Table table = (Table) clazz.getAnnotation(Table.class);
String tableName = table.value();
sb.append("select * from ")
.append(tableName)
.append(" where 1 == 1");
//3、遍历所有字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//4、处理每个字段对应的SQL
//4.1 获取字段的名字
isExists = field.isAnnotationPresent(Column.class);
if (!isExists) {
continue;
}
Column column = field.getAnnotation(Column.class);
String columnName = column.value();
//4.2 获取字段的值
String fieldName = field.getName();
String methodName = "get"
+ fieldName.substring(0, 1).toUpperCase()//首字母大写
+ fieldName.substring(1);
Object fieldValue = "";
try {
Method method = clazz.getMethod(methodName);
fieldValue = method.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
if (fieldValue == null ||
(fieldValue instanceof Integer && (Integer) fieldValue == 0)) {
continue;
}
//4.3 拼接SQL语句
sb.append(" and ")
.append(columnName)
.append(" = ");
if (fieldValue instanceof String) {//当前字段为字符串
sb.append("'")
.append(fieldValue)
.append("'");
} else if (fieldValue instanceof Integer) {//当前字段为整形
sb.append(fieldValue);
}//更多数据类型以此类推
}
sb.append(";");
return sb.toString();
}
测试:
public static void main(String[] args) {
User user = new User();//查询一个ID为"10086",名字为"张三",年龄为13的用户
user.setId("10086");
user.setName("张三");
user.setAge(13);
System.out.println(getSqlStatement(user));
Department department = new Department();//查询一个ID为"10010",名字为"行政部",人数为100的部门
department.setId("10010");
department.setName("行政部");
department.setAmount(100);
System.out.println(getSqlStatement(department));
}
运行结果: