java注解工作原理

1、什么是注解

注解是在jdk1.5版本引入的新特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量进行注解,注解也叫元数据,即是一种描述数据的数据,常见的注解有@override和@Deprecated。

2、注解的分类

2.1、java自带的标准注解

@Override:表明重写的某个方法

@Deprecated:表明某个类或是过时的方法

@SupperessWarnings:标明要忽略的警告

使用这些注解后编译器就会进行检查

2.2、元注解

用于定义注解的注解

  • @Retention:标明注解被保留的阶段(注解的生命周期)

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

枚举类RetentionPolicy:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}
RetentionPolicy.SOURCE:编译结束后失效如@Override

RetentionPolicy.CLASS:JVM加载类的时候失效,默认。不能 通 过反射获取

RetentionPolicy.RUNTIME:始终不失效,一般用于自定义注解,可通过反射获取
  • @Target:标明注解的使用范围

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

枚举类ElementType:

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
ElementType.TYPE:类、接口(包括注解类型)、枚举声明、用户自定义的注解

ElementType.FIELD:成员变量声明

ElementType.METHOD:方法声明

ElementType.PARAMETER:参数声明

ElementType.CONSTRUCTOR:构造方法声明

ElementType.LOCAL_VARIABLE:局部变量声明

ElementType.ANNOTATION_TYPE:注解类型声明

ElementType.PACKAGE:包声明

ElementType.TYPE_PARAMETER:类型参数声明

ElementType.TYPE_USE:任何类型名称声明
  • @Inherited:标明注解是可继承

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
  • @Documented:标明是否生成javadoc文档

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

2.3、自定义注解

根据自己的需求定义注解

3、注解的定义

3.1、定义:

注解就是用来描述包、类、成员变量、方法或者参数的元数据,注解本身也是一个类;例如Spring中的Bean,需要在xml中声明,比如说一个Bean的构造方法是啥,依赖哪些其他bean,初始化变量值是多少,这些都是描述性的数据告知Spring按照这个描述去创建这个Bean。

例如:

<bean id="Kenny" class="com.spring.User">
        <property name="height" value="186cm"></property>
        <property name="age" value="20"></property>
        <property name="name" ref="xjdh"></property> 
        <property name="hobby" ref="piano"></property> 
        <property name="hobby">
            <bean class="com.spring.Piano"></bean>
        </property>
    </bean>

这些对类和变量的表述实际上就是元数据,而现在这些都是可以用注解来取代。比如@Component注解标注在一个类上就可以说明该类是一个bean,@Autowire标注在成员变量上就直接给该成员变量赋值。看起来注解标注在代码上耦合性更强了,但实际上本着约定优于配置的原则,代码更加清晰,也容易维护。

3.2、XML和注解的区别

注解:是一种分散式的元数据,与源代码紧绑定。

XML:是一种集中式的元数据,与源代码无绑定

4、自定义注解

4.1、定义步骤

  1. @Target肯定要有
  2. @Retention生命周期一般为RUNTIME
  3. 用@interface声明
  4. 内部支持基本类型,String类型和枚举类型;
  5. 所有属性都必须写成field(),并可提供默认值default

4.2、使用注解

首先、在对应位置(@Target)标注;
然后、给注解中的属性赋值;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Company {
   public enum Status {RUNNING, CLOSED}
   String name() default "NETEASE"; //有默认值
   Status status() default Status.RIUNNING;
   String location();//没有默认值
} 
public class Demo{
    @Company(name="阿里巴巴",status=Company.Status.RUNNING,location="北京")
    public void companyInfo(){}
}
@interface Country{
  String value();
}
@Country("中国")
public void method(){};

4.3、注解标注完之后的处理

定义一个注解处理类和注解处理方法,所有这些对象都有getAnnotation()这个方法用来返回修饰它们的注解信息。因此可以通过反射获取注解标注的类或者方法或者变量等等并对其做相应处理;

import java.lang.reflect.Field;
public class AnnotationProccessor {
    public  static void process(Demo demo){
        Class demoClazz = Demo.class;
          for(Method method : demoClazz.getMethods()) {
             Company companyAnnotation = (Company)method.getAnnotation(Company.class);
             if(companyAnnotation !=null) {
                System.out.println(" Method Name : "+ method.getName());
                System.out.println(" name : "+ companyAnnotation.name());
                System.out.println(" Status : "+ companyAnnotation.status());
     }
  } 
}

5、参考文章

深入理解java注解