Java注解

来源:互联网 发布:淘宝乒乓球店 编辑:程序博客网 时间:2024/04/30 15:17

终于能好好写点东西了,暑假期间一直在忙着项目,每天地铁上来回4个小时,还都是高峰期,真是累。。。。今天这篇博客主要记录下自己对java注解的学习内容及心得!因为现在很多框架中都引用了大量的注解,我们学习注解就可以对那些代码的理解更上一个层次。而且,注解的使用也使得程序更加简洁。那么,好记性不如烂笔头嘛,还是得记下来以便以后查阅,哈哈!


1. Annotation概述:

Annontation是Java5.0版本开始引入的新特征。中文名称一般叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联,它可以应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中,为程序的元素加上更简单明了的说明。

2. Annotation原理:

Annotation其实是通过Java的反射机制相关的API来访问Annotation信息。相关类(框架或工具中的类即使用注解的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。

隔离性:Annotation是不会影响程序代码的执行,无论Annotation怎么变化,代码都始终如一地执行。

忽略性:Java语言解释器在工作时会忽略这些annotation,因此在JVM 中这些Annotation是“不起作用”的,只能通过配套的工具才能对这些Annontaion类型的信息进行访问和处理。

注解可分为3类:源码注解,编译时注解,运行时注解。

源码注解:注解只在源码中存在,编译成为.class文件就不存在了。

编译时注解:注解在源码和.class文件中都存在。像我们上面说的java自带的3种注解就是编译时注解,因为它们只在编译时起作用。

运行时注解:在运行阶段起作用,有可能还会影响运行逻辑。

还有一类叫做元注解的注解分类,也就是所谓的注解的注解,下面会详细说明。

3. java自带Annotation阐述:

java中自带的一些常见注解主要有3种:@Override,@Deprecated和@Suppvisewarnings。那么这3种注解分别代表什么意思以及如何使用?

  1. @Override

    java.lang.Override 是一个marker annotation类型,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。 这个annotaton常常在我们试图覆盖父类方法而却又写错了方法名时加一个保障性的校验过程。

  2. @Deprecated

    Deprecated也是一种marker annotation。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。所以使用这种修饰具有一定的 “延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为 @Deprecated,但编译器仍然要报警。

    例如当一个子类继承了父类的一个被标注了@Deprecated的方法后,编译器发出警告,说明此方法已经过时,不建议采用。此时为了去除编译器发出的警告,可以引用方法处添加@Suppvisewarnings注解。

    注意:@Deprecated这个annotation类型和javadoc中的 @deprecated这个tag是有区别的:前者是java编译器识别的,而后者是被javadoc工具所识别用来生成文档(包含程序成员为什么已经过时、它应当如何被禁止或者替代的描述)。

  3. @Suppvisewarnings

    此注解能告诉Java编译器关闭对类、方法及成员变量的警告。SuppressWarning不是一个marker annotation。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。

4. 自定义注解:

1).自定义注解的语法要求

@Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetenttionPolicy.RUNTIME)@Inherited@Documentedpublic @interface annotationDemo{    String name();    String address();    int age() default 20;}

如上面一个注解示例,使用@interface关键字定义注解,不是类,也不是接口。注解中的方法其实是相当于一个成员变量,且以无参数无异常的方式声明,还可以为成员指定一个默认值。并且成员类型是受限的,主要含有java的基本类型以及String,Class,Annotation,Enumeration。常用的一般是String和基本类型。另外,当注解只有一个成员时,成员固定取名为value,不能使用其他名字。如果注解类没有成员,那么这个注解就是标识注解。

2).元注解(注解的注解)

上面代码中的片段

@Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documented

就是元注解了。
@Target:表示注解的作用域,主要有(CONSTRUCTOR-构造方法声明,FIELD-字段声明,LOCAL_VARIABLE-局部变量声明,METHOD-方法声明,PACKAGE-包声明,PARAMETERH-参数声明和TYPE-类接口声明)
@Retention:表示注解类的生命周期分类:就是上述说明的源代码(RetentionPolicy.SOURCE),编译期(RetentionPolicy.CLASS)和运行时(RetentionPolicy.RUNTIME)三种生命周期。
@Inherited:标识注解,表示这个注解允许被子类即子注解继承。
@Documented:生成javadoc时会包含注解的相关信息

3).使用自定义注解
@<注解名>(<成员名1>=<成员值1>,<成员名2>=<成员值2>,…)

@annotationDemo(name="Ti2Yuan",address="Shanghai",age=24)public String personInfo(){   return "personInfo";}

如果注解只有一个成员时,则按如下使用
@<注解名>(<成员值>)

4).解析注解

通过反射获取类、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。

下面是一个解析注解的Demo,功能是组装SQL查询语句。

注解类Table,只含有一个成员

@Target({ElementType.TYPE})   //注解的使用范围  此处为类//注解的生命周期  主要有3种:源代码(class文件不存在),编译期(class文件存在),运行时@Retention(RetentionPolicy.RUNTIME)public @interface Table {    String value();}

注解类Column,同样只含有一个成员

@Target({ElementType.FIELD})   //注解的使用范围  此处为变量//注解的生命周期  主要有3种:源代码(class文件不存在),编译期(class文件存在),运行时@Retention(RetentionPolicy.RUNTIME)public @interface Column {    String value();}

使用注解的类Filter

@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;

解析注解:java 中提供了得到注解的api,如下面使用到的isAnnotationPresent和getAnnotation方法,其他的还有getAnnotations得到所有注解的方法。

public class Test {    public static void main(String[] args) {        Filter f1 = new Filter();        f1.setId(10);        Filter f2 = new Filter();        f2.setUserName("lucy");        f2.setAge(18);        String sql1 = query(f1);        String sql2 = query(f2);        System.out.println(sql1);        System.out.println(sql2);    }/** * 利用反射原理解析注解 * @param f * @return */    private static String query(Object f) {        StringBuilder sb = new StringBuilder();        //1.获取到class        Class c = f.getClass();        //2.获取到table的名字        boolean exists = c.isAnnotationPresent(Table.class);        if(!exists){            return null;        }        Table table = (Table) c.getAnnotation(Table.class);        String tableName = table.value();        sb.append("select * from ").append(tableName).append(" where 1=1");        //遍历所有字段        Field[] fields = c.getDeclaredFields();        for(Field field:fields){            //处理每个字段对应的sql            //拿到字段名            boolean fExists = field.isAnnotationPresent(Column.class);            if(!fExists){                continue;            }            Column column = field.getAnnotation(Column.class);            String columnName = column.value();            //拿到字段的值            String fieldName = field.getName();            String getMethodName = "get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);            Method getMethod;            Object fieldValue = null;            try {                getMethod = c.getMethod(getMethodName);                fieldValue = getMethod.invoke(f);            } catch (Exception e) {                e.printStackTrace();            }            //拼装sql            if(fieldValue == null || (fieldValue instanceof Integer && (Integer)fieldValue == 0)){                continue;            }            sb.append(" and ").append(fieldName).append("=");            if(fieldValue instanceof String){                if(((String) fieldValue).contains(",")){                    String[] values = ((String) fieldValue).split(",");                    sb.append(" in(");                    for(String value:values){                        sb.append("'").append(value).append("'").append(",");                    }                    sb.deleteCharAt(sb.length()-1);                    sb.append(")");                }else {                    sb.append("'").append(fieldValue).append("'");                                  }            }else {                sb.append(fieldValue);                          }        }        return sb.toString();    }}

运行之后的结果
select * from user where 1=1 and id=10
select * from user where 1=1 and userName=’lucy’ and age=18

感谢:
慕课网大_白的学习视频
http://josh-persistence.iteye.com/blog/2226493

0 0