1、java中常见的注解
jdk自带的注解:
@Override 覆盖父类方法
当发现父类的方法定义的有些问题,但是又不能删除,因为有些地方还在
调用这个接口则:
@Deprecated 表示方法已经过时
父类中设置方法过时:
@Suppvisewarnings 忽视方法过时的警告
当测试类调用时,会出现方法过时的警告,点击感叹号,添加忽视过时:
2、常见的第三方注解:
Spring :
@Autowired
@Service
@Repository
Mybatis :
@InterProvider
@UpdateProvider
@Options
3、注解的分类:
-->源码注解
注解只在源码中存在,编译成.class文件就没了
-->编译时注解
注解在源码和.class文件中存在
例如:@Override告诉编译器覆盖父类方法,然后进行编译
-->运行时注解
注解在运行阶段还起作用,影响运行逻辑
例如:@Autowired运行时把成员变量装配进来
元注解:给注解进行的注解
4、自定义注解:
声明:
元注解:
使用自定义注解:
5、解析注解:
通过反射获取类、函数或成员上的运行时注解信息,从而动态控制程序
运行的逻辑.
注解的继承:
父类中添加注解,子类中删除原有注解
此时还是用上面的解析方式对子类进行注解解析
所以要把Person改为类,而不是接口
child类中改为extends
运行 --> 打印出类上的注解,而不打印方法上的注解
所以注解只继承类上的注解,而不继承方法上的注解
6、项目实现:
需求:对象设置好要查询的条件,调用query()后返回对应的sql语句
Filter.java类:(对应了数据库表中各个字段)
Test实现类:(实现配置好查询条件,调用query返回sql)
对Filter类进行添加@Table和@Column两个注解之后,接下来对这两个注解
进行定义:(这里定义注解将对象与数据库中的表对应起来)
Table.java:(设置一个参数为表名,作用域为类或接口)
Column.java:(设置一个参数为列名,作用域为参数)
Test.java中query()方法的实现:(注意这里字段值有String和int类型,所以要定义为 Object类型)
现在如果有第二张表(Department.java),也需要这样的方式进行sql生成
则只需要在对应对象中添加@Table和@Column注解即可
只需要把query()方法中参数改为Object,这样就所有对象添加了注解的都有效了
jdk自带的注解:
@Override 覆盖父类方法
@Override
public String name() {
return null;
}
当发现父类的方法定义的有些问题,但是又不能删除,因为有些地方还在
调用这个接口则:
@Deprecated 表示方法已经过时
父类中设置方法过时:
@Deprecated
public void sing();
@Suppvisewarnings 忽视方法过时的警告
当测试类调用时,会出现方法过时的警告,点击感叹号,添加忽视过时:
@SuppressWarnings("deprecation")
public void sing(){
Person p = new child();
p.sing();
}
2、常见的第三方注解:
Spring :
@Autowired
@Service
@Repository
Mybatis :
@InterProvider
@UpdateProvider
@Options
3、注解的分类:
-->源码注解
注解只在源码中存在,编译成.class文件就没了
-->编译时注解
注解在源码和.class文件中存在
例如:@Override告诉编译器覆盖父类方法,然后进行编译
-->运行时注解
注解在运行阶段还起作用,影响运行逻辑
例如:@Autowired运行时把成员变量装配进来
元注解:给注解进行的注解
4、自定义注解:
声明:
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description{// 使用@interface关键字定义注
解
String desc();//成员以无参无异常方式声明
String author();
int age() default 18;//可以用default为成员指定一个默认值
}
元注解:
//注解作用域(构造方法、局部变量、方法声明、包声明类接口等)
@Target({ElementType.METHOD,ElementType.TYPE})
//注解的生命周期(源码、编译时、运行时)
@Retention(RetentionPolicy.RUNTIME)
//表示注解允许子类继承
@Inherited
//表示生成javadoc时会包含注解
@Documented
使用自定义注解:
@Description(desc="zy",author="boy",age=18)
public String eyeColor(){
return "red";
}
这样,@Description注解就在eyeColor()方法上使用5、解析注解:
通过反射获取类、函数或成员上的运行时注解信息,从而动态控制程序
运行的逻辑.
//1、使用类加载器加载类
try {
Class c = Class.forName
("com.ann.test.child");
//2、找到类上面的注解(判断指定类上是否存
在Description这个注解)
boolean isExist = c.isAnnotationPresent
(Description.class);
if(isExist){
//3、拿到注解实例
Description d = (Description)
c.getAnnotation(Description.class);
System.out.println(d.value());
}
//4、找到方法上的注解
//首先遍历所有的方法
Method[] ms = c.getMethods();
for (Method m : ms) {
//判断是否有注解
boolean isMExist =
m.isAnnotationPresent(Description.class);
if (isMExist) {
//如果存在则使用注解
Description md =
(Description)m.getAnnotation(Description.class);
System.out.println
(md.value());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
注解的继承:
父类中添加注解,子类中删除原有注解
此时还是用上面的解析方式对子类进行注解解析
此时运行不输出任何东西
原因是: @Inherited对于接口继承不起作用所以要把Person改为类,而不是接口
child类中改为extends
运行 --> 打印出类上的注解,而不打印方法上的注解
所以注解只继承类上的注解,而不继承方法上的注解
6、项目实现:
需求:对象设置好要查询的条件,调用query()后返回对应的sql语句
Filter.java类:(对应了数据库表中各个字段)
package com.zy.test;
@Table("user")
public class Filter {
@Column("id")
private int id;
@Column("user_name")
private String userName;
@Column("nick_name")
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 getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickNameString) {
this.nickName = nickNameString;
}
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;
}
}
Test实现类:(实现配置好查询条件,调用query返回sql)
package com.zy.test;
public class Test {
public static void main(String[] args) {
Filter f1 = new Filter();
f1.setId(10);//查询id为10的用户
Filter f2 = new Filter();
f2.setUserName("lucy");//模糊查询用户名为lucy的用
户
Filter f3 = new Filter();
f3.setEmail
("zy@sina.com,zy@163.com,888888@qq.com");//查询邮箱为其中任意一个
的用户
//调用query进行查询
String sql1 = query(f1);
String sql2 = query(f2);
String sql3 = query(f3);
System.out.println(sql1);
System.out.println(sql2);
System.out.println(sql3);
}
private static String query(Filter f){
return null;
}
}
对Filter类进行添加@Table和@Column两个注解之后,接下来对这两个注解
进行定义:(这里定义注解将对象与数据库中的表对应起来)
Table.java:(设置一个参数为表名,作用域为类或接口)
Column.java:(设置一个参数为列名,作用域为参数)
package com.zy.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value();
}
package com.zy.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
Test.java中query()方法的实现:(注意这里字段值有String和int类型,所以要定义为 Object类型)
package com.zy.test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
Filter f1 = new Filter();
f1.setId(10);//查询id为10的用户
Filter f2 = new Filter();
f2.setUserName("lucy");//查询用户名为lucy的用户
f2.setAge(19);
Filter f3 = new Filter();
f3.setEmail
("zy@sina.com,zy@163.com,888888@qq.com");//查询邮箱为其中任意一个
的用户
//调用query进行查询
String sql1 = query(f1);
String sql2 = query(f2);
String sql3 = query(f3);
System.out.println(sql1);
System.out.println(sql2);
System.out.println(sql3);
}
private static String query(Filter f){
StringBuilder sb = new StringBuilder();
//1、获取到class
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(" where 1=1 ");
//遍历所有的字段
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 columnNameString = column.value();
//4.2 拿到字段的值(通过反射取得get方法的名字,然
后通过反射区调用这个方法,就取得字段值)
String filedName = field.getName();
//把get加上字段名首字母大写
filedName.substring(0, 1).toUpperCase(),把首字母之后的名字内容拼
装上filedName.substring(1),就拼装成get方法
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) {
e.printStackTrace();
}
//拼装sql
//如果字段值为空或者字段值在int类型时为0
fieldValue instanceof Integer && (Integer)fieldValue == 0,将不作
处理
if (fieldValue == null || (fieldValue instanceof
Integer && (Integer)fieldValue == 0)) {
continue;
}
sb.append("and ").append(filedName);
if (fieldValue instanceof String) {
//如果是包含三个邮箱的查询,即包含逗号
if (((String) fieldValue).contains(","))
{
String[] value =
((String) fieldValue).split(",");
sb.append("in(");
for (String v : value) {
sb.append
("'").append(v).append("'").append(",");
}
//把最后一个逗号删掉
sb.deleteCharAt
(sb.length()-1);
sb.append(")");
}else{
sb.append("=").append
("'").append(fieldValue).append("'");
}
}
else if (fieldValue instanceof Integer) {
sb.append("=").append
(fieldValue);
}
}
return sb.toString();
}
}
现在如果有第二张表(Department.java),也需要这样的方式进行sql生成
则只需要在对应对象中添加@Table和@Column注解即可
Department.java:
package com.zy.test;
@Table("department")
public class Department {
@Column("id")
private int id;
@Column("name")
private String name;
@Column("leader")
private String leader;
@Column("number")
private int number;
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 String getLeader() {
return leader;
}
public void setLeader(String leader) {
this.leader = leader;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
只需要把query()方法中参数改为Object,这样就所有对象添加了注解的都有效了
Department d = new Department();
d.setId(1);
d.setLeader("kkk");
d.setNumber(111);
System.out.println(query(d));