Java 注解

1.1. 什么是注解

Java 注解(Annotation),又称 Java 标注,是 JDK5.0 引入的一种注释机制。Java 语言中的类、方法、变量、参数和包等都可以被标注。

Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

主要类都定义在 java.lang.annotation 包中。

1.2. 注解的作用

  • 标记、提示作用,例如 @Deprecated 标记某个类或方法不推荐使用,本身对代码无任何影响。 -

1.3. 注解的组成

java Annotation 的组成中,有 3 个非常重要的主干类。

  1. Annotation.java 这是所有注解的父类。类似于所有对象都默认实现Object.java类。具体可查看Annotation.java的源码说明。

  2. ElementType.java 这个枚举类定义了注解的出现位置(可以选择多个)。

  3. RetentionPolicy.java 这个枚举类定义了注解的生存期间(只能选择一个)。

1.4. 自定义注解

package world.wangxiao.learn.java.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author wangxiao
 */
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation {

}
  1. 使用 @interface 定义,从编译文件中可知道注解实际属于接口,但无法 `implements`其他类

  2. 通过@Retention 以及 RetentionPolicy.java 标记定义注解的生存期间

  3. 通过@Target以及 ElementType.java 标记定义注解的存在位置(Type:类,METHOD: 方法)

1.5. 注解的使用

注解的使用位置和定义注解时 @Target 标注的位置有关。

例如MyAnnotation只能用于类和方法头部:

package world.wangxiao.learn.java.annotation;

/**
 * @author wangxiao
 */
@MyAnnotation
public class AnnotationTest {

    @MyAnnotation
    public void test1() {

    }
}

1.6. 在注解中定义抽象方法

package world.wangxiao.learn.java.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author wangxiao
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation {

    int m1() default 0;

    String m2() default "hello";

    String m3();

}
  1. 返回值类型不能是 void 以及基本数据类型的包装类

  2. 没有 default 值时,使用该注解需要显示调用方法,见下面代码

package world.wangxiao.learn.java.annotation;

/**
 * @author wangxiao
 */
@MyAnnotation(m3 = "xx")
public class AnnotationTest {

    @MyAnnotation(m3 = "xx")
    public void test1() {

    }
}

1.7. 注解的应用场景

  1. 编译检查,注意通过编译器给出错误提示。

    1. @Override,如果有方法被@Override 标示,但父类中却没有”被 @Override 标注”的同名方法,则编译器会报错。

    2. @Deprecated,编译器会使用中划线标识出该函数。

  2. 通过给 Annotation 注解加上 @Documented 标签,能使该 Annotation 标签出现在 javadoc 中。

  3. 在反射的 Class, Method, Field 等函数中,有许多于 Annotation 相关的接口。(重点,spring框架很多功能都是结合注解以及反射来实现的)

  4. 通过 @Override, @Deprecated 等,我们能很方便的了解程序的大致结构。

1.8. 注解作用范围

注解的作用范围定义在 ElementType.java 中

public enum ElementType {
    /** 类、接口(包含注解)、枚举 */
    TYPE,

    /** 字段(包含枚举字段) */
    FIELD,

    /** 方法 */
    METHOD,

    /** 参数 */
    PARAMETER,

    /** 构造器 */
    CONSTRUCTOR,

    /** 本地变量 */
    LOCAL_VARIABLE,

    /** 注解类型 */
    ANNOTATION_TYPE,

    /** 包 */
    PACKAGE,

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

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

1.9. 结合 Target 注解使用

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * 返回值是一个数组,所以可以定义多个使用范围
     */
    ElementType[] value();
}

1.10. 生存范围

定义在 RetentionPolicy.java 类中

package java.lang.annotation;

public enum RetentionPolicy {
    // 只存在于源代码中,会被编译器抛弃
    SOURCE,

    // 能被编译器编译到class文件中,但是无法被虚拟机所检测到。默认行为。
    CLASS,

    //  能被编译器编译到class文件中,且能被虚拟机所检测到
    RUNTIME
}

配合 Rention 注解使用

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    // 返回值为RetentionPolicy,只能有一个。
    RetentionPolicy value();
}

1.11. JDK 常用注解

1.11.1. @Deprecated

@Deprecated 所标注内容,不再被建议使用。在类上加则表示整个类不推荐使用,在方法上加,则表示方法不推荐使用。如果我们使用这个注解标记类或者方法,一定要指明新的替代类或者方法。

1.11.2. @Override

@Override 只能标注方法,表示该方法覆盖父类中的方法。

1.11.3. @Documented

@Documented 所标注内容,可以出现在javadoc中。

1.11.4. @Inherited

@Inherited只能被用来标注"`Annotation类型`",它所标注的Annotation具有继承性。

1.11.5. @Retention

@Retention只能被用来标注"`Annotation类型`",而且它被用来指定Annotation的RetentionPolicy属性。

1.11.6. @Target

@Target只能被用来标注"`Annotation类型`",而且它被用来指定Annotation的ElementType属性。

1.11.7. @SuppressWarnings

@SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。

deprecation  -- 使用了不赞成使用的类或方法时的警告
unchecked    -- 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型。
fallthrough  -- 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告。
path         -- 在类路径、源文件路径等中有不存在的路径时的警告。
serial       -- 当在可序列化的类上缺少 serialVersionUID 定义时的警告。
finally      -- 任何 finally 子句不能正常完成时的警告。
all          -- 关于以上所有情况的警告。
SpellCheckingInspection -- idea 拼写错误。

例如,如果方法中调用了一个被申明已废弃的方法,编辑器会显示中划线,在方法头部加上@SuppressWarnings(value=\{“deprecation”}),中划线就会消失。

1.12. 感悟

注解需要配合反射来实现很多逻辑功能。可看作为一种标记,程序运行时,可以通过反射查找需要的标记,然后获取信息,完成很多功能。

参考:https://www.runoob.com/w3cnote/java-annotation.html