Java-注解

Java 注解(Annotation) | 菜鸟教程 (runoob.com)

Java注解(Annotation)又称Java标注,可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。JVM可以保留标注内容,在运行时可以获取到标注内容。

支持自定义Java标注。

内置的注解

Java定义了一套注解,有7个,3个在java.lang中,4个在java.lang.annotation中。

作用在代码的注解是

  • @Override

    检查该方法是否是重写方法

  • @Deprecated

    标记过时方法,使用该方法时会报编译警告

  • @SuppressWarnings

    指示编译器去忽略注解中声明的警告

作用在其他注解的注解(或者说 元注解)是:

  • @Retention

    标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问

  • @Documented

    标记这些注解是否包含在用户文档中

  • @Target

    标记这个注解应该是哪种Java成员

  • @Inherited

    标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

从Java7开始,额外添加了3个注解:

  • @SafeVarargs

    Java7开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告

  • @FunctionalInterface

    Java8开始支持,标识一个匿名函数或函数式接口

  • @Repeatable

    Java8开始支持,标识某注解可以在同一个声明上使用多次

Annotation架构

Annotation架构

  • 一个Annotation和一个RetentionPolicy(策略属性)关联

    可以理解为:每个Annotation对象,都会有唯一的RetentionPolicy属性。

  • 一个Annotation和1~n个ElementType关联

    可以理解为:对于每个Annotation对象,可以有若干个ElementType属性。

  • Annotation有许多实现类 ,包括:Deprecated、Documented、Inherited、Override等等

    Annotation的每个实现类,都“和1个 RetentionPolicy 关联” 并且 “和 1~n 个 ElementType 关联”

图中左侧部分

Annotation左侧部分

1
2
3
4
5
6
7
8
9
//Annotation.java

package java.lang.annotation;
public interface Annotation{
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
//ElementType.java

package java.lang.annotation;
public enum ElementType{
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
PARAMETER, /* 参数声明 */
CONSTRUCTOR, /* 构造方法声明 */
LOCAL_VARIABLE, /* 局部变量声明 */
ANNOTATION_TYPE, /* 注释类型声明 */
PACKAGE /* 包声明 */
}
1
2
3
4
5
6
7
8
//RetentionPolicy.java

package java.lang.annotation;
public enum RetentionPolicy{
SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */
CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */
RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}

注意:@Retention(RetentionPolicy.Class)Annotation的默认行为

  • 例子: @Override

    1
    2
    3
    4
    5
    6
    7
    package java.lang;
    import java.lang.annotation.*;

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    • 修饰方法的时候,意味着该方法覆盖父类的方法。
    • 在编译期间进行语法检查!【编译处理完后,@Override就没作用了】
  • 自定义注解

    1
    2
    3
    4
    5
    @Documented
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation1{
    }
    • @interface

      是必须的。意味着它就是个实现了(实现细节由编译器完成)java.lang.annotation.AnnotationAnnotation注解。

      注意:它和 implemented 实现接口不同。通过 @interface 定义注解后,该注解不能继承其他的注解或接口。

    • @Documented

      非必须。类和方法的 Annotation 在缺省情况下不会出现在 javadoc 中。使用了 @Documented 后就可以出现在 javadoc 中。

    • @Target(ElementType.TYPE)

      非必须。若有@Target,则该 Annotation 只能用在它指定的地方;若没有 @Target,则该Annotation可用于任何地方。

    • @Retention(RetentionPolicy.RUNTIME)

      非必须。指定 Annotation 的策略属性。如果没有 @Retention,则默认是 RetentionPolicy.CLASS 类型

图中右侧部分

Annotation右侧

右侧是Java自带的Annotation

1
2
3
4
5
6
7
@Deprecated  -- @Deprecated 所标注内容,不再被建议使用。
@Override -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
@Documented -- @Documented 所标注内容,可以出现在javadoc中。
@Inherited -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。
@Retention -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
@Target -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
@SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。

定义MyAnnotation(有@Inherited)。父类用MyAnnotation注解,则子类也具有了MyAnnotation注解。

如果MyAnnotation(没有@Inherited),则父类有MyAnnotation注解,子类没有MyAnnotation注解。

SupressWarnings常用的关键字的表格

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

import java.util.Date;
public class SupressWarningTest{
@SuppressWarnings(value={"deprecation"})
public static void doSomething(){
Date date = new Date(113, 8, 26);
System.out.println(date);
}

public static void main(String[] args){
doSomething();
}
}