Java注解
概念:Java提供了一种原程序中的元素关联的任何信息和任何元数据的途经和方法。
Java中常见的注解
JDK自带注解 | @Override 覆盖父类的方法 |
@Deprecated 表示这个方法已经过时了 //这个方法已经过时了 @Deprecated public void sing(); | |
@Suppvisewarnings //忽略过时的警告 @SuppressWarnings("deprecation") public void test(){ Person p = new Child(); p.sing(); } | |
常见第三方注解 Spring | @Autowired |
@Service | |
@Repository | |
常见第三方注解 Mybatis | @InsertProvider |
@UpdateProvider | |
@Options |
实现接口类不会自动添加@Override 注解,解决方法:
右键项目-> Java Compiler –> Compiler compliance level –> 1.7
Java注解的分类
按照运行机制分 | 源码注解:注解只在源码中存在,编译成class文件就没有了。 |
编译时注解:注解在源码和.class 文件中都存在。如: @Override @Deprecated @Suppvisewarnings | |
运行时注解: 在运行阶段还起作用,甚至会影响运行逻辑的注解。 如@Autowired | |
按照来源划分 | 来自JDK的注解 |
来自第三方的注解 | |
我们自己定义的注解 | |
元注解 | 注解的注解 |
自定义注解的语法要求
/*
* 下面四个注解为元注解
* @Target标识注解的作用域:可配置的值为
* CONSTRUCTOR(构造方法声明)FIELD(字段声明)LOCAL_VARIABLE(局部变量声明)
* METHOD(方法声明) PACKAGE(包声明) PARAMETER(参数声明) TYPE(类,接口)
* @Retention 注解的生命周期,可选的值有
* SOURCE(只在源码显示,编译时会丢弃)
* CLASS(编译时会记录到class中,运行时忽略)
* RUNTIME(运行时存在,可以通过反射读取)
* @Inherited 允许子类继承,继承时只会继承类上面的注解
* @Documented 生成javadoc时会包含注解的信息
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
/*使用@interface 关键字定义注解*/
public @interface Description{
/*
*1.成员的类型是受限的,合法的类型包括原始类型及String,Class
*Annotation,Enumeration
*2.如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略
*成员名和赋值号(=)
*3.注解类可以没有成员,没有成员的注解称为标识注解
*/
String desc();//成员以无参无异常方式声明
String author();
int age() default 18; //可以用default为成员指定一个默认值
}
//如何使用注解
class UseAnn{
@Description(desc="I am eyeColor",author="meng",age=24)
public String eyeColor(){
return "red";
}
}
解析注解
通过反射获取类、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。
在Child类上加上注解@Description(desc="I am a class annotation")
public class Child implements Person{
@Description(desc="I am a method annotation")
@Override
public String name() {
// TODO Auto-generated method stub
return null;
}
@Override
public int age() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void sing() {
// TODO Auto-generated method stub
}
}
public class ParseAnn {
public static void main(String[] args) {
//1. 使用类加载器加载类
try{
Class c = Class.forName("com.ann.test.Child");
//2. 找到类上面的注解
boolean isExist = c.isAnnotationPresent(Description.class);
if(isExist){
//3. 拿到注解实例
Description d = (Description)c.getAnnotation(Description.class);
System.out.println(d.desc());
}
//4.找到方法上的注解
Method[] ms = c.getMethods();
for(Method method : ms){
boolean isMExist = method.isAnnotationPresent(Description.class);
if(isMExist){
Description d = (Description)method.getAnnotation(Description.class);
System.out.println(d.desc());
}
}
//另一种解析方法
for(Method m : ms){
//获取所有的注解
Annotation[] as = m.getAnnotations();
for(Annotation a : as){
if(a instanceof Description){
Description d = (Description) a;
System.out.println(d.desc());
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
注解实战
需求:
1. 有一张用户表,字段包括用户ID,用户名,昵称,年龄,性别,所在城市,邮箱,手机号。
2. 方便对每个字段或字段的组合条件进行检索,并打印出SQL。
3. 使用方式要足够简单。
首先创建Filter.java类,指定和数据库对应的字段。并加上注释
@Table("user")
public class Filter {
@Column("id")
private int id;
@Column("usrName")
private String usrName;
@Column("nickName")
private String nickName;
@Column("age")
private int age;
@Column("city")
private String city;
@Column("email")
private String email;
@Column("mobile")
private String mobile;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsrName() {
return usrName;
}
public void setUsrName(String usrName) {
this.usrName = usrName;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
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;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
创建表注解 Table.java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
//只有一个方法,则名字用value,这是一个约定
String value();
}
创建字段注解 Column.java
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
使用注解拼接SQL语句 Test.java
public class Test {
public static void main(String[] args) {
Filter f1 = new Filter();
f1.setId(10);//查询id为10 的用户
Filter f2 = new Filter();
f2.setUsrName("lucy");//查询用户名为lucy的用户
Filter f3 = new Filter();
f3.setEmail("liu@sina.com,zh@163.com,aa@qq.com");//查询邮箱为其中任意一个的记录
String sql1 = query(f1);
String sql2 = query(f2);
String sql3 = query(f3);
System.out.println(sql1);
System.out.println(sql2);
System.out.println(sql3);
/**
* 假如这里有了一个Filter2 类,描述了另一个表的内容,我们这里还是可以直接使用
*/
Filter2 f4 = new Filter2();
f4.setLeader("Dancy");
f4.setId(12);
String sql4 = query(f4);
System.out.println(sql4);
}
private static String query(Object f){
StringBuilder sb = new StringBuilder();
//1.获取到Class
Class c = f.getClass();
//2.获取到table的名字
boolean isExist = c.isAnnotationPresent(Table.class);
if(!isExist){
return null;
}
Table t = (Table) c.getAnnotation(Table.class);
String tableName = t.value();
// where 1=1 为拼接的技巧
sb.append("select * from ").append(tableName).append(" where 1=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 = (Column) field.getAnnotation(Column.class);
String columnName = column.value();
//4.2 拿到字段的值
String filedName = field.getName();
//拼接出get方法的名字
String getMehodName = "get"+filedName.substring(0,1).toUpperCase()+filedName.substring(1);
Object filedValue = null;
try {
//根据方法名字用反射获取方法对象
Method getMethod = c.getMethod(getMehodName);
filedValue = getMethod.invoke(f, null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//4.3拼装sql
if(filedValue == null ||
(filedValue instanceof Integer && (Integer)filedValue == 0)){
continue;
}
sb.append(" and ").append(filedName);
//如果是String类型的sql语句需要拼接上单引号
if(filedValue instanceof String){
//如果字符串中包含逗号,则说明是email
if(((String)filedValue).contains(",")){
String[] values = ((String)filedValue).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("'"+filedValue+"'");
}
}else if(filedValue instanceof Integer){
sb.append(" = ").append(filedValue);
}
}
return sb.toString();
}
}
SQL拼接结果,我们还可以实现更复杂的SQL拼接