Java自定义注解

概念

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();
	}
}

执行测试程序,输出结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值