【JAVA 基础】自定义注解

摘要:注解是一种能被添加到 Java 代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。本篇文章主要介绍了注解的基本语法及注意事项,对元注解的四个注解进行了详细的解释说明。使用 @Target 元注解表示我们的注解作用的具体范围和目标,使用 @Retention 表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)等。

注解的概念

官方对注解的描述:

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

翻译:

注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。

通过官方的描述,可以得出以下结论:

  • Java 注解用于为 Java 代码提供元数据。元数据在开发中的作用就是做数据约束和标准定义,可以将其理解成代码的规范标准(代码的模板)。
  • 代码的模板(元数据)不直接影响代码的执行,它只是帮助我们来更快捷的开发。
  • 注解可以标记在包、类、属性、方法,方法参数以及局部变量上,且同一个地方可以同时标记多个注解。

基本语法

  • 声明部分:注解在Java中,与类、接口、枚举类似,因此其声明语法基本一致,只是所使用的关键字有所不同@interface。在底层实现上,所有定义的注解都会自动继承java.lang.annotation.Annotation接口。
public @interface Annotation {
}
  • 实现部分:根据我们在自定义类的经验,在类的实现部分无非就是书写构造、属性或方法。但是,在自定义注解中,其实现部分只能定义一个东西:注解类型元素(annotation type element)。
public @interface Annotation {
public String name();
// 与接口中定义抽象方法的语法是不同的
 int age() default 18;
 int[] array();
}

关于实现部分注解类型元素,与接口中定义抽象方法的语法是不一样,需要注意以下几点:

  • 访问修饰符必须为public,不写默认为public;
  • 该元素的类型只能是基本数据类型、String、Class、枚举类型、注解类型(体现了注解的嵌套效果)以及上述类型的一位数组;
  • 如果注解中只有一个元素,请把名字起为value( String value() default "");
  • ()不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法;
  • default代表默认值,值必须和之前定义的类型一致;
  • 如果没有默认值,代表后续使用注解时必须给该类型元素赋值。

元注解

自定义注解的时候,需要使用元注解(专门修饰注解的注解)来进行注解,具体使用到以下四个注解。

@Target

使用 @Target 元注解表示我们的注解作用的具体范围和目标,可以是类、方法、变量等,同样也是通过枚举类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
     * 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *类型使用,可以用于标注任意类型除了 class (jdk1.8加入)
     * @since 1.8
     */
    TYPE_USE
}

@Retention

Retention 英文意思有保留、保持的意思,它表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)。

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * 注解将被编译器忽略掉,仅存在于源码中,在class字节码文件中不包含。
     */
    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文件中,但在运行时不会被虚拟机保留,这是一个默认的行为。
     */
    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.
     * 注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到。
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

在 @Retention 注解中使用枚举 RetentionPolicy 来表示注解保留时期:

  • @Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含。
  • @Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得。
  • @Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到。

@Documented

Document 的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。

package java.lang.annotation;

/**
 * Indicates that annotations with a type are to be documented by javadoc
 * and similar tools by default. This type should be used to annotate the
 * declarations of types whose annotations affect the use of annotated
 * elements by their clients. If a type declaration is annotated with
 * Documented, its annotations become part of the public API
 * of the annotated elements.
 *
 * @author Joshua Bloch
 * @since 1.5
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Inherited

Inherited 的英文意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。

package java.lang.annotation;

/**
 * Indicates that an annotation type is automatically inherited. If
 * an Inherited meta-annotation is present on an annotation type
 * declaration, and the user queries the annotation type on a class
 * declaration, and the class declaration has no annotation for this type,
 * then the class's superclass will automatically be queried for the
 * annotation type. This process will be repeated until an annotation for this
 * type is found, or the top of the class hierarchy (Object)
 * is reached. If no superclass has an annotation for this type, then
 * the query will indicate that the class in question has no such annotation.
 *
 * <p>Note that this meta-annotation type has no effect if the annotated
 * type is used to annotate anything other than a class. Note also
 * that this meta-annotation only causes annotations to be inherited
 * from superclasses; annotations on implemented interfaces have no
 * effect.
 *
 * @author Joshua Bloch
 * @since 1.5
 * @jls 9.6.3.3 @Inherited
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

使用示例

自定义注解Page页面:

package com.wangxiong.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Page {
    /**
     * 用于绑定的请求参数名字
     */
    String value() default "";
}

相关推荐

Leave a Reply

Your email address will not be published. Required fields are marked *

微信扫一扫,分享到朋友圈

【JAVA 基础】自定义注解
返回顶部

显示

忘记密码?

显示

显示

获取验证码

Close