【Java注解】@Retention的作用和@Target注解的说明以及使用方法

本文目录

一、注解说明

二、@Target注解

三、@Retention注解

3.1 注解源码

3.2 注解的作用

3.3 如何选择

四、自定义注解


一、注解说明

注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

定义注解时,会需要一些元注解(meta--annotation),如@Target@ Retention,这两个特性是我们必须要定义清楚的,一个是Target(注解目标),另一个就是Retention(注解生命周期,也叫声明周期)。

@Target用来定义你的注解将应用于什么地方(例如是一个方法或者一个域)。

@ Retention用来定义该注解在哪一个级别可用,在源代码中(SOURCE)类文件中(CLASS)或者运行时(RUNTIME)

在注解中,一般都会包含一些元素以表示某些值。当分析处理注解时,程序或工具可以利用这些值。注解的元素看起来就像接口的方法,唯一的区别是你可以为其指定默认值。

没有元素的注解称为标记注解(marker annotation),例如我在文章尾部自定义的注解。

Java目前只内置了三种标准注解(下一篇文章介绍),以及四种元注解。元注解专职负责注解其他的注解。

二、@Target注解

下面是注解@Target的源码,这里要一个ElementType[]数组。

 /**
  * @since 1.5
  * @jls 9.6.4.1 @Target
  * @jls 9.7.4 Where Annotations May Appear
  */
@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是枚举类型的,一共有10种取值类型,分别是(TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE)以下是ElementType的源码:

 /**
  * @author  Joshua Bloch
  * @since 1.5
  * @jls 9.6.4.1 @Target
  * @jls 4.1 The Kinds of Types and Values
  */
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
}

三、@Retention注解

3.1 注解源码

如下是@Retention注解的源码信息,它要求一个RetentionPolicy类型的取值。我们再看看RetentionPolicy是个什么类型对象。

/** 
 * @author  Joshua Bloch
 * @since 1.5
 * @jls 9.6.3.2 @Retention
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

点击进入 RetentionPolicy 对象之后,发现它是一个枚举类型的,有三种取值(SOURCE, CLASS, RUNTIME),以下是 RetentionPolicy 枚举源码:

/**
 * @author  Joshua Bloch
 * @since 1.5
 */
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
}

3.2 注解的作用

注解 @Retention 可以用来修饰注解,是注解的注解,这样的注解被称为元注解。

@Retention 注解有一个属性 value,是 RetentionPolicy 类型的,Enum RetentionPolicy 是一个枚举类型,从上面源码中可以看到。

这个枚举决定了 Retention 注解应该如何去保留,也可理解为 @Retention 搭配枚举类型 RetentionPolicy 使用。

按生命周期来划分可分为3类:

1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成 .class 文件的时候,被其标注的注解被遗弃;

2、RetentionPolicy.CLASS:注解被保留到class文件中,但jvm加载 .class 文件时候,被其标注的注解会被遗弃,这是默认的生命周期;

3、RetentionPolicy.RUNTIME:注解不仅被保留到 .class 文件中,jvm 加载 .class 文件之后,被其标注的注解仍然存在,所以这个时候才可能通过反射机制读取注解的信息,而前两个生命周期中,通过反射机制读取不到注解信息的;

这3个生命周期分别对应于:Java源文件(.java文件) ---> .class文件 ---> 内存中的字节码。

3.3 如何选择

那怎么来选择合适的注解生命周期呢?

首先要明确生命周期长度 RUNTIME > CLASS > SOURCE,所以后者能作用到的地方前者一定也能作用到,但是反过来,前者能作用到的地方后者就作用不到。

1、一般如果需要在运行时去动态获取注解信息,那只能用生命周期最长的 RUNTIME 标注了,比如 @Deprecated 就是使用 RetentionPolicy.RUNTIME 来标注的;

比如以下源码中我们常用到的注解:@Transient、@Deprecated、@Documented、@Inherited、@Retention、@Target ... 等等很多。

注解 @Deprecated,用来表示某个类或属性或方法已经过时,不想别人再用时,在属性和方法上用 @Deprecated 修饰。

2、如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;

这个在源码中没有找到,但是参考其他博客写的 ButterKnife 就是被 RetentionPolicy.CLASS 标注的。

3、如果只是做一些检查性的操作,比如源码中的 @Override、@SuppressWarnings、@Native、@Generated 等就是被 RetentionPolicy.SOURCE 标注的。

使用注解 @Override 用在方法上,当我们想重写一个方法时,在方法上加 @Override,当我们方法的名字出错时,编译器就会报错。

使用注解 @SuppressWarnings 用来压制程序中出来的警告,比如在没有用泛型或是方法已经过时的时候。

四、自定义注解

看完源码之后,发现自定义注解其实也不难,比葫芦画瓢,我们也自定义注解试一下。

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface TestAnnotation {

}

定义完之后,就可以使用自己定义的注解了,例如:

@TestAnnotation
public class Sort {

    public static void main(String[] args) {
        System.out.println("自定义注解使用中.....");
    }

}

【参考资料】

Thinking in Java(Fouth Edition) ---- Java编程思想(第四版):第20章 注解

Java注解:三种标准注解和四种元注解以及注解的元素:https://blog.csdn.net/weixin_44299027/article/details/105920418

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

No8g攻城狮

向每一个努力改变现状的你致敬!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值