概念
Java提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法
Java中的常见注解
JDK中的注解
@Deprecated:方法过时
package com.itcast.mybatis.pojo;
public interface Person {
public String name();
public int age();
/*
* @Deprecated:方法过时
*/
@Deprecated
public void sing();
}
@Override:重写父类的方法
package com.itcast.mybatis.pojo;
public class Child implements Person{
@Override
public String name() {
// TODO Auto-generated method stub
return null;
}
@Override
public int age() {
// TODO Auto-generated method stub
return 0;
}
/*
*@Override:重写父类的方法
*/
@Override
public void sing() {
// TODO Auto-generated method stub
}
}
@SuppressWarnings:忽略警告
package com.itcast.mybatis.test;
import com.itcast.mybatis.pojo.Child;
import com.itcast.mybatis.pojo.Person;
public class TestCase {
/*
*@SuppressWarnings:忽略警告
*/
@SuppressWarnings("deprecation")
public void sing() {
Person p=new Child();
p.sing();
}
}
常见第三方注解
注解的分类
按照运行机制分
- 源码注解
注解只在源码中存在,编译成.class文件就不存在了
- 编译时注解
注解在源码和.class文件中都存在
@Override
@Deprecated:
@SuppressWarnings
- 运行时注解
在运行阶段还起作用,甚至会影响运行逻辑的注解
@Autowired
按照来源分
- 来自JDK的注解
- 来自第三方的注解
- 我们自己定义的注解
元注解
给注解的注解
自定义注解
- 使用@interface关键字定义注解
- 成员以无参无异常方式声明
- 可以用default为成员指定一个默认值
- 成员类型是受限的,合法的类型包括原始类型及String,Class,Annotation,Enumeration
- 如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=)
- 注解类可以没有成员,没有成员的注解称为标识注解
@Target:自定义注解的作用域
- TYPE:类,接口
- FIELD:字段声明
- MRTHOD:方法声明
- PARAMETER:参数声明
- CONSTRUCTOR:构造方法声明
- LOCAL_VARIABLE:局部变量声明
- PACKAGE:包声明
@Retention:生命周期
- RetentionPolicy.SOURCE :只在源码显示,编译时会丢弃
- RetentionPolicy.CLASS: 编译时会记录到class中,运行时忽略
- RetentionPolicy.RUNTIME:运行时存在,可以通过反射读取
@Inherited 允许子类以注解的方式继承
@Documented :生成javadoc时会包含注解的信息
自定义注解的使用
使用注解的语法:
@注解名(成员名=成员值,成员名=成员值)
@Target注解的使用
@Retention注解的使用
创建注解
package com.itcast.mybatis.pojo;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
String value();
}
使用注解
package com.itcast.mybatis.pojo;
@Description("I am class annotation")
public class Child implements Person{
@Description("I am method annotation")
public String name() {
return null;
}
@Override
public int age() {
return 0;
}
/*
*@Override:重写父类的方法
*/
@Override
public void sing() {
}
}
解析注解
通过反射获取类、函数或成员上的运行时注解信息,
从而实现动态控制程序运行的逻辑
package com.itcast.mybatis.test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import com.itcast.mybatis.pojo.Description;
public class ParseAnn {
public static void main(String[] args) {
// 1. 使用类加载器加载类
try {
// Class.forName(类的全名)
Class c = Class.forName("com.itcast.mybatis.pojo.Child");
// 2. 找到类上面的注解
boolean isExist = c.isAnnotationPresent(Description.class);
if (isExist) {
// 3. 拿到注解实例
Description d = (Description) c.getAnnotation(Description.class);
System.out.println("类上的注解:\t" + d.value());
}
// 4. 找到方法上的注解
Method[] m = c.getMethods();
for (Method method : m) {
boolean isMExist = method.isAnnotationPresent(Description.class);
if (isMExist) {
Description d = (Description) method.getAnnotation(Description.class);
if (d != null) {
System.out.println("方法上的注解:\t" + d.value());
}
}
}
// 另外一种解析方法
// 1.先获得所有的方法的注解,再使用instanceof判断方法的类型
for (Method method : m) {
Annotation[] as = method.getAnnotations();
for (Annotation a : as) {
if (a instanceof Description) {
System.out.println("另外一种方法获得方法上的注解:\t" +((Description) a).value());
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
执行测试程序,控制台输出如下结果:
修改Description类的生命周期
再次执行上述测试程序com.itcast.mybatis.test.ParseAnn,控制台什么都没有输出
再次执行上述测试程序com.itcast.mybatis.test.ParseAnn,控制台什么都没有输出
@Inherited注解的使用
1.创建注解
package com.itcast.mybatis.pojo;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
/**
*自定义注解Description
* @author 86182
*
*/
public @interface Description {
String value();
}
2.注解的使用
package com.itcast.mybatis.pojo;
@Description("I am interface")
public class Person {
@Description("I am interface method")
public String name() {
return null;
}
public int age() {
return 0;
}
/*
* @Deprecated:方法过时
*/
@Deprecated
public void sing() {
}
}
package com.itcast.mybatis.pojo;
public class Child extends Person{
public String name() {
return null;
}
@Override
public int age() {
return 0;
}
/*
*@Override:重写父类的方法
*/
@Override
public void sing() {
}
}
3.测试程序
package com.itcast.mybatis.test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import com.itcast.mybatis.pojo.Description;
public class ParseAnn {
public static void main(String[] args) {
// 1. 使用类加载器加载类
try {
// Class.forName(类的全名)
Class c = Class.forName("com.itcast.mybatis.pojo.Child");
// 2. 找到类上面的注解
boolean isExist = c.isAnnotationPresent(Description.class);
if (isExist) {
// 3. 拿到注解实例
Description d = (Description) c.getAnnotation(Description.class);
System.out.println("类上的注解:\t" + d.value());
}
// 4. 找到方法上的注解
Method[] m = c.getMethods();
for (Method method : m) {
boolean isMExist = method.isAnnotationPresent(Description.class);
if (isMExist) {
Description d = (Description) method.getAnnotation(Description.class);
if (d != null) {
System.out.println("方法上的注解:\t" + d.value());
}
}
}
// 另外一种解析方法
// 1.先获得所有的方法的注解,再使用instanceof判断方法的类型
for (Method method : m) {
Annotation[] as = method.getAnnotations();
for (Annotation a : as) {
if (a instanceof Description) {
System.out.println("另外一种方法获得方法上的注解:\t" + a);
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
4. 执行测试程序,输出结果
总结
@Inherited修饰的注解,子类继承此自定的注解,只作用于类上,方法上不起作用
@Inherited修饰的注解,接口继承此自定义的注解,类实现接口时不会继承任何接口中定义的注解
练习
有一张用户表,字段包括:用户ID、用户名、昵称、年龄、性别、所在城市、邮箱、手机号;
使用java注解来对用户表的每个字段或字段的组合条件进行动态生成SQL查询语句。
自定义注解@Table
package com.liyu.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();
}
自定义注解@Column
package com.liyu.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();
}
定义映射到数据库的bean
package com.liyu.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 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;
}
}
测试程序
package com.liyu.test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.swing.text.FieldView;
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("liu@sina.com,zh@163.com,77777@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);
}
@SuppressWarnings("unchecked")
private static String query(Filter f) {
StringBuilder sb = new StringBuilder();
try {
// 1.获取到Class
Class c = Class.forName("com.liyu.test.Filter");
// 2.获取到table的名字
boolean isExist = c.isAnnotationPresent(Table.class);
if (!isExist) {
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[] fArry = c.getDeclaredFields();
for (Field field : fArry) {
// 4.处理每个字段对应的sql
// 4.1拿到字段名
boolean fExists = field.isAnnotationPresent(Column.class);
if (!fExists) {
continue;
}
Column column = field.getAnnotation(Column.class);
String columnName = column.value();
// 4.2拿到字段的值
String filedName = field.getName();
String getMethodName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
Object filedValue = null;
try {
Method getMethod = c.getMethod(getMethodName);
// java反射
filedValue = getMethod.invoke(f);
} catch (Exception e) {
e.printStackTrace();
}
// 4.3拼装sql
if (filedValue == null || (filedValue instanceof Integer && (Integer) filedValue == 0)) {
continue;
}
sb.append(" and ").append(filedName);
if (filedValue instanceof String) {
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("'").append(filedValue).append("'");
}
} else if (filedValue instanceof Integer) {
sb.append("=").append(filedValue);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return sb.toString();
}
}