Java 注解基本原理

注解的本质

「java.lang.annotation.Annotation」接口中有这么一句话,用来描述『注解』。html

The common interface extended by all annotation types
全部的注解类型都继承自这个普通的接口(Annotation)

这句话有点抽象,但却说出了注解的本质。咱们看一个 JDK 内置注解的定义:java

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

这是注解 @Override 的定义,其实它本质上就是:数组

public interface Override extends Annotation{
}

没错,注解的本质就是一个继承了 Annotation 接口的接口。有关这一点,你能够去反编译任意一个注解类,你会获得结果的。app

一个注解准确意义上来讲,只不过是一种特殊的注释而已,若是没有解析它的代码,它可能连注释都不如。ide

解析一个类或者方法的注解每每有两种形式,一种是编译期直接的扫描,一种是运行期反射。code

元注解

『元注解』是用于修饰注解的注解,一般用在注解的定义上。htm

JAVA 中有如下几个『元注解』:对象

  • @Target:注解的做用目标
  • @Retention:注解的生命周期
  • @Documented:注解是否应当被包含在 JavaDoc 文档中
  • @Inherited:是否容许子类继承该注解

@Target

@Target 注解指明该注解能够做用哪些对象上。blog

@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数组,ElementType是一个枚举,成员以下:继承

  • ElementType.TYPE:容许被修饰的注解做用在类、接口和枚举上
  • ElementType.FIELD:容许做用在属性字段上
  • ElementType.METHOD:容许做用在方法上
  • ElementType.PARAMETER:容许做用在方法参数上
  • ElementType.CONSTRUCTOR:容许做用在构造器上
  • ElementType.LOCAL_VARIABLE:容许做用在本地局部变量上
  • ElementType.ANNOTATION_TYPE:容许做用在注解上
  • ElementType.PACKAGE:容许做用在包上
  • ElementType.TYPE_PARAMETER:容许做用在类型参数上
  • ElementType.TYPE_USE:容许做用在类型上

@Retention

@Retention 用于指明当前注解的生命周期

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

注解接收一个RetentionPolicy数据,RetentionPolicy是个枚举,成员以下:

  • RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件
  • RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件
  • RetentionPolicy.RUNTIME:永久保存,能够反射获取

JAVA 的内置三大注解

  • @Override
  • @Deprecated 标识类或方法再也不推荐使用
  • @SuppressWarnings 主要用来压制 java 的警告

实现一个本身的注解

定义一个注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HelloAnnotation {
    String value() default "Hello annotation!";
}

使用这个注解:

public class UseAnnotation {

    @HelloAnnotation
    public void hello() {
        System.out.println("hello");
    }

    @HelloAnnotation("Hello world!")
    public void helloWorld() {
        System.out.println("Hello world!");
    }
}

注解最重要的部分在于对注解的处理。注解处理器就是经过反射机制获取被检查方法上的注解信息,而后根据注解元素的值进行特定的处理。若是没有注解处理器,注解就是个注释,或者连注释都不如。

处理这个注解:

public class Test {

    public static void main(String[] args) {
        testAnnotation(UseAnnotation.class);
    }

    private static void testAnnotation(Class<?> cl) {
        for (Method m : cl.getDeclaredMethods()) {
            HelloAnnotation ha = m.getAnnotation(HelloAnnotation.class);
            if (ha != null) {
                System.out.println("Found My Annotation: " + ha.value());
            }
        }
    }
}

输出结果:

Found My Annotation: Hello annotation!
Found My Annotation: Hello world!

参考资料

JAVA 注解的基本原理
Java注解基本原理

相关文章
相关标签/搜索