[笔记]Java注解全面解析

来源:互联网 发布:国际服务器端口定义 编辑:程序博客网 时间:2024/05/17 05:14

JAVA注解

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

1.注解分类

1.1按照运行机制分类

  1. 源码注解
    注解只在源码中存在,编译成.class文件就不存在了
  2. 编译时注解
    注解在源码和.class文件中都存在
    比如:
    @Override    @Deprecated    @Suppvisewarnings
  1. 运行时注解
    在运行阶段还起作用,甚至会影响运行逻辑的注解。

1.2.按照来源分类

  1. 来自JDK的注解
  2. 来自第三方的注解
  3. 我们自己定义的注解

2.自定义注解

2.1.自定义注解的语法要求

  1. 在类上使用@interface关键字定义注解
  2. 成员以无参无异常方式声明
  3. 可以用default为成员指定一个默认值
  4. 成员类似是受限的,合法的类型包括原始类型以及String,Class,Annotation,Enumeration
  5. 如果注解只有一个成员,则成员名必须取名为Value(),在使用时可以忽略成员名和赋值号(=)
  6. 注解类可以没有成员,没有成员的注解称为标识注解

2.2.注解的注解(元注解)

是注解的注解,称为元注解

  1. Retention注解
    这种类型的注解会被保留到那个阶段,
    RetentionPolicy.SOURCE : 只在源码显示,编译时会丢弃
    RetentionPolicy.CLASS :编译时会记录到class中,运行时忽略
    RetentionPolicy.RUNTIME : 运行时存在,可以通过反射读取
  2. Inherited 注解
    允许子类继承,
    标识一个普通类继承一个父类,但是这个父类被该一个自定义注解(自定义注解上面有Inherited注解)标注的时候,子类可以继承父类上的注解
  3. Documented 注解
    生产Javadoc的时候包含注解(默认是不包含的)
  4. Target 注解
    标识该注解的作用域,例如:ElementType.Type 就只能标注在class类上面

2.3.使用自定义注解

  1. 使用注解的语法
    @注解名(成员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 = "默认出生";  //商品的初始化信息介绍}
  1. 定义具体的商品类
/** 商品苹果 */public class Apple extends Goods{    public int price = 10; //价格}
  1. 开始解析演示获取注解上面的信息
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
原创粉丝点击