[笔记]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

写到最后

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

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

时间: 2024-10-20 22:21:57

[笔记]Java注解全面解析的相关文章

Java注解全面解析(转)

1.基本语法 注解定义看起来很像接口的定义.事实上,与其他任何接口一样,注解也将会编译成class文件. @Target(ElementType.Method) @Retention(RetentionPolicy.RUNTIME) public @interface Test {} 除了@符号以外,@Test的定义很像一个空的接口.定义注解时,需要一些元注解(meta-annotation),如@Target和@Retention @Target用来定义注解将应用于什么地方(如一个方法或者一个

java注解(Annotation)解析

注解(Annotation)在java中应用非常广泛.它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ模式代替Schema模式,特别是最近接触了一点Spring MVC,每次编写Controller的时候用@RequestMapping(),@RequestParam,@ResponseBody等等. 我们所用的java中自带的注解都是定义好了的,直接拿来用,它就能发挥作用.当然了,自己也可以定义注

Java注解全面解析

1.基本语法 注解定义看起来很像接口的定义.事实上,与其他任何接口一样,注解也将会编译成class文件. @Target(ElementType.Method) @Retention(RetentionPolicy.RUNTIME) public @interface Test {} 除了@符号以外,@Test的定义很像一个空的接口.定义注解时,需要一些元注解(meta-annotation),如@Target和@Retention @Target用来定义注解将应用于什么地方(如一个方法或者一个

java注解方式解析xml格式

注解类和字段方式: @XStreamAlias("message") 别名注解 注解集合: @XStreamImplicit(itemFieldName="part") 比如说要注解下面这个xml: <conditions> <condition queryType="33106"> <item> <name>corpName</name> <value></value

java注解学习笔记

今天看了下有关java注解的视频学习资料在.做点笔记: 学java注解的目的: 能看别人代码,特别是框架代码.由于肯定与注解有关. 编程更简洁,代码清晰. java注解是java1.5引入的:注解概念是java提供的一种原程序中的元素关联不论什么信息和元数据的途径和方法. 常见注解(编译时注解); @override:方法覆盖了它的父类的方法 @Deprecated:这个凝视是一个标记凝视. 所谓标记凝视.就是在源程序中增加这个标记后,并不影响程序的编译.但有时编译器会显示一些警告信息. 或者在

【iMooc】全面解析java注解

在慕课上学习了一个关于java注解的课程,下面是笔记以及一些源码. Annotation--注解 1.JDK中的注解 JDK中包括下面三种注解: @Override:标记注解(marker annotation),重写,父类写的方法,如果子类继承了父类,就要重写父类的方法. @Deprecated:表示过时的语法加上这个注解之后,该方法上会出现一道删除线 @SuppressWarning:忽略警告,压制警告.如果某语句前面出现警告,加上这个注解,警告就会消失. 举例如下: 父类 一个Person

java基础巩固笔记(6)-注解

java基础巩固笔记(6)-注解 java基础巩固笔记6-注解 注解的应用结构图 元注解 自定义注解 示例代码 参考资料 注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在包.类.字段.方法.局部变量.方法参数等的前面,用来对这些元素进行说明,注释. API Package java.lang.annotation 注解的应用结构图 调用/结构关系:A<–B<–C A,B,C解释如下: A:注解类

Java基础笔记 – Annotation注解的介绍和使用 自定义注解

Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 |  被围观 25,969 views+ 1.Annotation的工作原理:2.@Override注解:3.@Deprecated注解:4.@SuppressWarnings注解:5.自定义注解:5.1.添加变量:5.2.添加默认值:5.3.多变量使用枚举:5.4.数组变量:6.设置注解的作用范围:6.1.在自定义注解中的使用例子:7.使用反射读取R

java笔记--String类对象解析与运用

1.String中的equals和==的区别 String是对象而非基本数据类型,不能使用"=="来判断两个字符串是否相当, 判断两个字符串内容是否相同用equals(); 判断两个字符串内存地址是否相同用"==" 2.startsWith(String str): 判断字符串是否以str为前缀 3.endsWith(String str): 判断字符串是否以str为后缀 4.String 字符串的比较: 1).compareTo()和compareToIgnore