码迷,mamicode.com
首页 > 编程语言 > 详细

[笔记]Java注解全面解析

时间:2015-07-25 20:02:44      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:java   注释   注解   自定义   

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

写到最后

本例子很简陋。本人反射也没学好。将就着看吧

版权声明:本文为博主原创文章,未经博主允许不得转载。

[笔记]Java注解全面解析

标签:java   注释   注解   自定义   

原文地址:http://blog.csdn.net/mr_zhuqiang/article/details/47056901

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!