注解的好处:
1、 易懂别人写的代码
2. 让编程更加简单简洁,代码更加清晰.
3、 适用于业务逻辑(自定义注解)
注解概念:
Java 提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法.
(一)Jva中的常见注解:Jdk自带的注解:
1.@override (覆盖)
2.@deprecated (过时)
3.@suppvisewarnings (忽略警告)
示例展示:
1.创建Person类------>2.创建孩子Child类------>3.创建测试类
(1)
public interface Person {
public String name();
public int age();
//2.加上@Deprecated这个注解,表示这个方法已经过时了(然后就自动带上灰色横线)
@Deprecated
public void sing();
}
(2)public class Child implements Person{
//1.当孩子类继承person类的时候,系统会提示加上@Override注解,此时@Override注解告诉我们,也告诉编译器当前类的name方法已经覆盖了person类的方法
@Override
public String name() {
return null;
}
@Override
public int age() {
return 0;
}
@Override
public void sing() {
System.out.println("二狗会唱歌");
}
}
(3)
public class test {
//3.此时想要在调用这个唱歌的sing方法,就得加上@SuppressWarnings("deprecation"),该注解会忽略警告的功能
@SuppressWarnings("deprecation")
public static void main(String[] args) {
// TODO Auto-generated method stub
Person a=new Child();
a.sing();
}
}
运行结果:
二狗会唱歌
第三方注解:Spring:
1.@Autowired (自动生成一个xxx(dao)的实例注入进去)
2.@Service
3.@Repository
Mybatis: @Inserprovider(插入)
@UpdateProvider(更新)
@Options
(二)注解的分类注解运行机制分类:
源码注解:-----注解只在源码中存在,在编译成.class文件就不存在了.
编译时注解:-----在.clas文件中都存在.注解信息(@override,@deprecated,@suppvisewarnings)
运行时注解:-----运行阶段还起作用,还会影响运行逻辑的注释(@Autowired)
元注解:注解的注解.(三)自定义注解
元注解:
@Target({ElemenetType.METHOD.ElemenetType.type})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
示例1
成员类型是受限的.合法的类型包括原始类型及String,Class,Annotation,enumeration
public @interface Description{//使用@interface关键字定义注解 String desc(); //无参数无异常方式声明
String author();
int age() default 18;//可以用default默认给成员指定一个值
}
@Target({ElemenetType.METHOD.ElemenetType.type}) 注解的作用域.(用在什么地方)
ElemenetType.CONSTRUCTOR 构造器声明
ElemenetType.FIELD 域声明(包括 enum 实例)ElemenetType.LOCAL_VARIABLE 局部变量声明
ElemenetType.ANNOTATION_TYPE 作用于注解量声明
ElemenetType.METHOD 方法上可以声明
ElemenetType.PACKAGE 包声明
@Retention(RetentionPolicy.RUNTIME) 声明周期
ElemenetType.PARAMETER 参数声明
ElemenetType.TYPE 类上,接口(包括注解类型)或enum都可以声明RetentionPolicy.SOURCE 注解源码中显示,编译时被丢弃
RetentionPolicy.CLASS 注解会记录到class文件中,运行时忽略
RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解。@Inherited 允许子类继承父类中的注解(标识类的注解)
@Documented 将此注解包含在 javadoc 中 .
它代表着此注解会被javadoc工具提取成文档。
在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
使用注解的语法:
@<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>.....)
@Description 注解是在eyeClor方法上使用
示例2(结合示例1):
@Description(desc="I am eyeColor",author="zhangsan",age=90)
public String eyeClor{ return "red";
}
真实示例:
Description自定义的注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
@Target({ElementType.METHOD,ElementType.TYPE})//作用域有两个,说明在方法和类上都可以声明
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
String value(); //只有一个成员的时候
}
Child类:
public class Child implements Person{
@Override
@Description("zhang") //这只有一个成员的使用,声明在了方法上
publicString name() {return null;
}
...
}
-解析注解
概念:通过反射,获取类,函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑.
示例3:
Description自定义的注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
@Target({ElementType.METHOD,ElementType.TYPE})//作用域有两个,说明在方法和类上都可以声明
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public@interface Description {
String value(); //只有一个成员的时候
}
//自定义的孩子类
@Description("I am class Annotation")//分别在类上添加注解<--------
publicclass Child implements Person{
@Override
@Description("I am method Annotation")//添加注解<--------
public String name() {
//TODO Auto-generated method stub
returnnull;
}
@Override
@Description("I am method Annotation2")//添加注解<--------
publicint age() {
//TODO Auto-generated method stub
return 0;
}
@Override
publicvoid sing() {
//TODO Auto-generated method stub
System.out.println("二狗会唱歌");
}
}
测试解析注解类:
import java.lang.reflect.Method;import java.text.Annotation;public class ParseAnn {public static void main(String[] args) {try {//一找到类注解//1.使用类加载器加载类Class c=Class.forName("Child");//类的路径,找到那个类用了个注解,找到它//2.找到类上的注解是否存在,存在就去拿实例boolean isExist=c.isAnnotationPresent(Description.class);if (isExist) {//3.拿到注解实例Description d=(Description)c.getAnnotation(Description.class);System.out.println("类上的注解==="+d.value());}//二.找到方法注解Method[] ms=c.getMethods(); for (Method m : ms) { boolean isMExist=m.isAnnotationPresent(Description.class); if (isMExist) { Description d=(Description)m.getAnnotation(Description.class); System.out.println("方法上的注解==="+d.value());}} } catch (Exception e) {// TODO: handle exception}}}
打印结果:
类上的注解===I am class Annotation
方法上的注解===I am method Annotation
方法上的注解===I am method Annotation2
(四)注解实战----实战需求:
1.有一张用户表,字段包括用户ID,用户名,昵称,年龄,性别,所在城市,邮箱,手机号.
2.方便对每个字段或字段的组合条件进行检索,并打印出sql
示例:
自定义2两个注解:一个用于类,一个用于字段
Table.java文件
(一)作用于类接口
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();
}
(二)作用于字段Column.java文件
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();
}
写一个filter类(相当于普通的用户类把注解用进去):
Filter.java文件
@Table("user") //标识的表明,用一个值就可以了
public class Filter {
@Column("id")
private int id;
@Column("user_name")
private String userName;//用户名
@Column("nike_name")
private String nikeName;//昵称
@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 getNikeName() {
return nikeName;
}
public void setNikeName(String nikeName) {
this.nikeName = nikeName;
}
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;
}
}
再写一个filter2类(也使用@table注解)
Filter2.java文件
@Table("department") //部门
public class Filter2 {
@Column("id")
private int id;
@Column("name")
private String name;//名字
@Column("leader")
private String leader;//领导
@Column("amount")
private int amount;//人数
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 getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
测试类
test.java文件
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class test {
public static void main(String[] args) {
//初始化
Filter f1 =new Filter();
f1.setId(10);//查询id是10的用户
Filter f2 =new Filter();
f2.setUserName("liudehua");//查询用户名为loudehua的用户
Filter f3 =new Filter();
//f3.setEmail("kaka@163.com,哈哈哈@163.com,heihei@163.com");//查询kaka
f3.setEmail("kaka@163.com");//查询kaka
//执行
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 ff=new Filter2();
ff.setAmount(10);
ff.setName("技术部");
String sqlff = Query(ff);
System.out.println(sqlff);//打印输出结果
}
//Query查询方法返回sql字符串
private static String Query(Object f) {
//定义接收返回的字符串初始化
StringBuilder sb=new StringBuilder();
//获取到class
Class c=f.getClass();
boolean isexit=c.isAnnotationPresent(Table.class);
if (!isexit) {
return null;
}
Table t=(Table)c.getAnnotation(Table.class);
String tableName=t.value();
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=field.getAnnotation(Column.class);
String ColumnNanme=column.value();
//4.2拿到字段值
String filedName=field.getName();
//拿到一个字母大写+后面的部分
String getMeThodName="get"+filedName.substring(0,1).toUpperCase()+filedName.substring(1);
//System.out.println("//拿到一个字母大写+后面的部分getMeThodName=="+getMeThodName);
Object fieldValue =null;
try {
Method getMethod=c.getMethod(getMeThodName);
//反射调用
fieldValue =getMethod.invoke(f, null);
} catch (Exception e) {
e.printStackTrace();
}
//4.3拼装sql
//判断如果fieldValue等于null,或它是整型并且等于0的时候不做处理
if (fieldValue ==null || (fieldValue instanceof Integer && (Integer)fieldValue ==0)) {
continue;
}
sb.append(" and ").append(filedName);
//判断fieldValue是String类型的时候做+上""
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 if(fieldValue instanceof Integer){
//整形
sb.append("=").append(fieldValue);
}
}
return sb.toString();//返回拼接好的串儿
}
}
输出结果:
select *fromuser where 1=1 and id=10
select *fromuser where 1=1 and userName='liudehua'
select *fromuser where 1=1 and email='kaka@163.com'
select *fromdepartment where 1=1 and name='技术部' and amount=10
实战示例可直接复制代码,自行测试.