java注解基础
java中可能你经常能在ide中看到@Override,但是很少关心它是什么?而在使用spring框架时能使用注解,会让spring注入变得简洁。
- 注解的概念:java提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法。
java常见注解
- Jdk自带常用注解
- @Override 重写
- @Deprecated 弃用(调用会产生的结果)
- @SuppressWarnings(“deprecation”) 忽略警告
注解分类
- 按照运行机制分类:
- 源码注解:注解只在源码中存在,编译为class文件就不存在了
- 编译时注解:注解在源码和class文件中都存在(上面3个)
- 运行时注解:运行阶段还在起作用,甚至影响运行时逻辑的注解
- 元注解:理解为注解的注解
自定义注解
注解语法(注意查看注释内的说明)
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;
/**
* 使用@interface关键字定义注解
*
* 1、成员的类型是受限制的,合法的类型包括原始类型,及String,Class,Annotation,Enumeration
* 2、如果注解只有一个成员,则成员名必须取名为value(),在使用注解时可以忽略成员名和赋值号(=)
* 3、注解类可以没有成员,没有成员的注解称为标识注解
*/
/**
* 元注解
*@Target是注解的作用域(使用时能够放在哪个地方),作用域列表{CONSTRUCTOR:构造方法声明 FIELD:字段声明 LOCAL_VARIABLE:局部变量声明
* METHOD(方法头上):方法声明 PACKAGE:包声明 PARAMETER:参数声明 TYPE:类接口}
*
*@Retention 生命周期,注解的分类,SOURCE(源码显示,编译丢弃),
* CLASS(编译会记录到class,运行忽略),
* RUNTIME(运行时存在,可以通过反射读取)
*
*@Retention 标识性注解,允许子类继承
*@Documented 生成javadoc时会包含注解信息
**/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
/**
* 成员以无参无异常的方式声明
*/
String desc();
String author();
/**
* 可以用default为成员指定一个默认值
*/
int age() default 18;
}
使用语法:
public class Test {
@Description(desc="一个方法",author="tom",age=18)
public void man() {
//
}
}
解析注解
概念:通过反射来获取类,函数或者成员上的运行时注解信息,从而实现动态的控制程序运行的逻辑。
//注解文件:
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
String value();
}
//-----------------抽象父类---------
/**
* 只会继承类上的注解
* 不会继承方法的注解
*/
@Description("i am super class")
public abstract class Person {
@Description("i am interface method annotation")
public abstract String name();
public abstract int age();
@Deprecated
public abstract void sing();
}
//-------------------子类继承-----------------
public class Child extends Person{
@Override
public String name() {
// TODO 自动生成的方法存根
return null;
}
@Override
public int age() {
// TODO 自动生成的方法存根
return 0;
}
@Override
public void sing() {
// TODO 自动生成的方法存根
}
}
//----------------------解析代码-----------
import java.lang.reflect.Method;
/**
* 解析的前提是@Retention(RetentionPolicy.RUNTIME)
*
*/
public class ParseAnn {
public static void main(String[] args) {
try {
//1、使用类加载器加载类
Class class1 = Class.forName("annotation_study02.Child");
//2、找到类上的注解实例
boolean isExist = class1.isAnnotationPresent(Description.class);
if (isExist) {
//3、拿到注解实例
Description d = (Description)class1.getAnnotation(Description.class);
System.out.println(d.value());
}
//4、找到方法上面的注解
Method[] ms = class1.getMethods();
for(Method m:ms) {
boolean is = m.isAnnotationPresent(Description.class);
if (is) {
Description dm = (Description)m.getAnnotation(Description.class);
System.out.print(dm.value()+"\n");
}
}
//第二种解析方法
for(Method m:ms) {
java.lang.annotation.Annotation[] as = m.getAnnotations();
for(java.lang.annotation.Annotation a:as) {
if(a instanceof Description) {
Description description = (Description) a;
System.out.print(description.value());
}
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
结果:
分析:注解@Description,被元注解@Inherited修饰,所以可以被继承,但是只能继承类上的注解,方法的注解无效。
将Child类里的注解修改一下,并去掉Person上的所有注解。
//增加
@Description("i am class annotation")
public class Child extends Person{
//增加
@Description("i am method annotation")
@Override
public String name() {
// TODO 自动生成的方法存根
return null;
}
@Override
public int age() {
// TODO 自动生成的方法存根
return 0;
}
@Override
public void sing() {
// TODO 自动生成的方法存根
}
}
再运行一次结果:
一个综合练习:
注解类:
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();
}
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();
}
一个javabean:
@Table("filter_table")
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;
}
}
一个测试类:
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Filter filter1 = new Filter();
filter1.setId(10); //查询id为10的用户
Filter filter2 = new Filter();
filter2.setUserName("lucy"); //模糊查询用户名为lucy的用户
Filter filter3 = new Filter();
filter3.setEmail("123@qq.com,234@163.com,mm@sina.com");//查询其中一个邮箱
String sql1 = query(filter1);
String sql2 = query(filter2);
String sql3 = query(filter3);
System.out.println(sql1);
System.out.println(sql2);
System.out.println(sql3);
}
public static String query(Filter filter) {
StringBuilder sql = new StringBuilder();
//1、获取class
Class c = filter.getClass();
//2、获取Table的名字
boolean flagT = c.isAnnotationPresent(Table.class);
if(!flagT) {
return null;
}
Table table = (Table)c.getAnnotation(Table.class);
String tableName = table.value();
sql.append("select * from ").append(tableName).append(" where 1=1");
//3、遍历所有的字段
Field[] fs = c.getDeclaredFields();
for(Field f : fs) {
//处理每个字段的对应sql
boolean flagC = f.isAnnotationPresent(Column.class);
if(!flagC) {
continue;
}
//拿到字段的名
Column column = (Column)f.getAnnotation(Column.class);
String columnName = column.value();
//拿到字段的值
String fname = f.getName();
String getMethodName = "get"+fname.substring(0, 1).toUpperCase()+fname.substring(1);
Object fieldValue = null;
try {
Method m = c.getMethod(getMethodName);
fieldValue = m.invoke(filter);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
//拼装sql
if(fieldValue==null||
(fieldValue instanceof Integer&&(Integer)fieldValue==0)) {
continue;
}
sql.append(" and ").append(columnName);
if(fieldValue instanceof String) {
if(((String) fieldValue).contains(",")) {
String[] eString = ((String) fieldValue).split(",");
sql.append("=in(");
for(String e:eString) {
sql.append("'").append(e).append("'").append(",");
}
sql.deleteCharAt(sql.length()-1);
sql.append(")");
}else {
sql.append("=").append("'").append(fieldValue).append("'");
}
}
else if(fieldValue instanceof Integer) {
sql.append("=").append(fieldValue);
}
}
return sql.toString();
}
}
结果: