[笔记]Java注解全面解析
来源:互联网 发布:国际服务器端口定义 编辑:程序博客网 时间:2024/05/17 05:14
JAVA注解
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
1.注解分类
1.1按照运行机制分类
- 源码注解
注解只在源码中存在,编译成.class文件就不存在了 - 编译时注解
注解在源码和.class文件中都存在
比如:
@Override @Deprecated @Suppvisewarnings
- 运行时注解
在运行阶段还起作用,甚至会影响运行逻辑的注解。
1.2.按照来源分类
- 来自JDK的注解
- 来自第三方的注解
- 我们自己定义的注解
2.自定义注解
2.1.自定义注解的语法要求
- 在类上使用@interface关键字定义注解
- 成员以无参无异常方式声明
- 可以用default为成员指定一个默认值
- 成员类似是受限的,合法的类型包括原始类型以及String,Class,Annotation,Enumeration
- 如果注解只有一个成员,则成员名必须取名为Value(),在使用时可以忽略成员名和赋值号(=)
- 注解类可以没有成员,没有成员的注解称为标识注解
2.2.注解的注解(元注解)
是注解的注解,称为元注解
- Retention注解
这种类型的注解会被保留到那个阶段,
RetentionPolicy.SOURCE : 只在源码显示,编译时会丢弃
RetentionPolicy.CLASS :编译时会记录到class中,运行时忽略
RetentionPolicy.RUNTIME : 运行时存在,可以通过反射读取 - Inherited 注解
允许子类继承,
标识一个普通类继承一个父类,但是这个父类被该一个自定义注解(自定义注解上面有Inherited注解)标注的时候,子类可以继承父类上的注解 - Documented 注解
生产Javadoc的时候包含注解(默认是不包含的) - Target 注解
标识该注解的作用域,例如:ElementType.Type 就只能标注在class类上面
2.3.使用自定义注解
- 使用注解的语法
@注解名(成员1=成员值1,成员2=成员2值….)
接下来,编写一个自定义注解
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.TYPE,ElementType.FIELD}) //可以让本注解标识在类上,和属性上@Retention(RetentionPolicy.RUNTIME) //表示在运行时可以获取该注解@Inherited //标识一个普通类继承一个父类,但是这个父类被Person注解标注的时候,子类可以继承父类上的注解类型@Documented //生产javadoc的时候,包含注解public @interface Desc { String detail(); //详细描述信息 String value() default "这个人很懒,什么都没有留下";}
解析注解
通过反射获取类、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑
下面通过完成一个获取商品信息的小栗子来介绍下注解的解析
1. 定义一个父类,抽象商品的信息
/** * 商品信息父类 */@Desc(value="抽象类Goods类上的value值",detail="抽象类Goods类上的详细描述")public abstract class Goods { @Desc(detail="抽象类Goods属性上的详细描述") public String initInfo = "默认出生"; //商品的初始化信息介绍}
- 定义具体的商品类
/** 商品苹果 */public class Apple extends Goods{ public int price = 10; //价格}
- 开始解析演示获取注解上面的信息
public class Test { public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException { Apple apple = new Apple(); Class<? extends Apple> c = apple.getClass(); //获 取类上的指定类型注解 boolean flag = c.isAnnotationPresent(Desc.class); if(flag){ //该类上面是否存在Desc 注解,@Inherited在这里就能看出来了,如果没有这个注解,这里是获取不到desc注解的 Desc classType = c.getAnnotation(Desc.class); System.out.println(classType.value() + "," + classType.detail()); } //获取属性上面的值 Field[] fields = c.getFields(); for (Field field : fields) { if(field.isAnnotationPresent(Desc.class)){ Desc d = field.getAnnotation(Desc.class); //@Inherited 这里更加能看到,父类上的注解信息完全被继承了 System.out.println("属性:" + field.getName() + "上的注解的信息是:" + d.value() + d.detail()); } } }}
执行结果:
抽象类Goods类上的value值,抽象类Goods类上的详细描述
属性:initInfo上的注解的信息是:这个人很懒,什么都没有留下抽象类Goods属性上的详细描述
3.综合小栗子
模拟一个简单的hibernate使用实体对象生成sql语句的例子
1.编写模拟表的注解
/** 模拟表的信息 **/@Target({ ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)public @interface Table { String value();}
2.编写模拟字段信息的注解
/** 模拟表字段信息 */@Target({ ElementType.FIELD })@Retention(RetentionPolicy.RUNTIME)public @interface Column { String value();}
3.编写条件查询的对象
/** 条件查询对象 **/public class Filter { public static final String GT = "gt"; // 大于 > // 装条件映射值 private Map<KV, String> map = new HashMap<KV, String>(); /** 设置条件 * @param key 属性名称 * @param value 对应的值 * @param type 查询的条件,默认为 == 。 */ public void setValue(String key, String value,String type) { map.put(new KV(key,value), type); } public Map<KV, String> getMap() { return map; };}class KV { private String k; private String v; public KV(String k, String v) { super(); this.k = k; this.v = v; } public String getK() { return k; } public void setK(String k) { this.k = k; } public String getV() { return v; } public void setV(String v) { this.v = v; }}
4.编写实体类,使用我们自己编写的注解来映射表的信息
@Table("tab_apple")public class Apple { @Column("apple_name") private String name; // 名称 @Column("apple_price") private double price; // 价格 public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; }}
5.测试和编写生成sql的代码
import java.lang.reflect.Field;import java.util.Map;public class Test { public static void main(String[] args) throws NoSuchFieldException, SecurityException { Filter f = new Filter(); f.setValue("name", "苹果", null); f.setValue("price", "5", Filter.GT); String sql = query(f, Apple.class); //这里查询name=苹果并且价格大于 5 的商品信息的语句 System.out.println(sql); // 打印生成的sql语句 } /** * 生成sql语句 * * @param f * 条件对象 * @param clzz * 实体表的类型 * @return * @throws SecurityException * @throws NoSuchFieldException */ public static String query(Filter f, Class<?> clzz) throws NoSuchFieldException, SecurityException { // 1:获取实体上的注解信息,先生成基本的查询语句 if (!clzz.isAnnotationPresent(Table.class)) { throw new RuntimeException("请传入一个实体类"); } Table table = clzz.getAnnotation(Table.class); String tableName = table.value(); boolean flag = false; // 追加sql的时候,标记sql语句后面是否已经有sql了 StringBuffer sb = new StringBuffer(); sb.append("select * from ").append(tableName); // 2:获取条件所有的条件 Map<KV, String> map = f.getMap(); for (Map.Entry<KV, String> ent : map.entrySet()) { KV kv = ent.getKey(); String type = ent.getValue(); Field field = clzz.getDeclaredField(kv.getK()); // 获取条件属性对应的属性对象 if (!field.isAnnotationPresent(Column.class)) { // 如果此属性不包含column注解标识,抛出异常 throw new RuntimeException("传入的参数有误"); } Column column = field.getAnnotation(Column.class); ; if (flag) { sb.append(" and ").append(parse(column.value(), kv.getV(), type)); } else { flag = true; sb.append(" where ").append(parse(column.value(), kv.getV(), type)); } } return sb.toString(); } /** * 解析条件sql * * @param k * 数据库表中的字段名称 * @param v * 值 * @param type * 条件类型 * @return */ public static String parse(String k, String v, String type) { String sql = ""; if (type != null) { if (type.equals(Filter.GT)) { sql = k + " > " + v; } } else { sql = k + " = " + v; } return sql; }}
执行结果:
select * from tab_apple where apple_name = 苹果 and apple_price > 5
写到最后
本例子很简陋。本人反射也没学好。将就着看吧
0 0
- [笔记]Java注解全面解析
- 全面解析Java注解(学习笔记)
- 全面解析Java注解--慕课网笔记
- 全面解析Java注解
- 全面解析Java注解
- 全面解析Java注解
- 全面解析 Java 注解
- 全面解析Java注解
- 全面解析Java注解
- Java注解全面解析
- 全面解析Java注解
- Java注解全面解析
- Java 注解全面解析
- 全面解析java注解
- 全面解析Java注解
- 全面解析Java注解
- 全面解析Java注解
- 全面解析Java注解
- 时间复杂度
- 全面解析《嵌入式程序员应该知道的16个问题》
- 判断语句常量放前面
- 墨西拿中文离线地图App上线
- overridePendingTransition设置Activity切换动画
- [笔记]Java注解全面解析
- 关于Javascript游戏按键操控移动的思考
- 素数的判断
- uva10404 Bachet’s Game(dp之取石子游戏的胜负)
- Java基础之集合类常见试题
- 147 Insertion Sort List
- 循环队列的顺序表示和实现
- OpenCV Machine Learning 之正态贝叶斯分类器(Normal Bayes Classifier)的用法实例
- 冒泡排序法