Java语言注解(Annotation)简介

时间:2020-12-19 20:15:05

Java语言中的注解(Annotation)是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符,可用来将信息元数据与程序元素进行关联。

注解主要分为两种类型,即:

1)标记型注解(Marker Annotation)

这种注解仅用自身的存在与否来为我们提供信息,更通俗一点来说,就是这个注解不带任何成员变量。

2)元数据注解

这种注解可以接受更多的元数据,其实就是包含了成员变量的注解。

Java语言默认自带了三个注释:

1)@Override

限定被注解的方法必须是重写父类的方法。对于子类中被@Override 修饰的方法,如果存在对应的被重写的父类方法,则正确,如果不存在,则报错。@Override 只能作用于方法,不能作用于其他程序元素。

2)@SuppressWarnings

抑制编译器警告。指示被@SuppressWarning修饰的程序元素,以及该程序元素中的所有子元素(例如类以及该类中的方法)取消显示指定的编译器警告。

@SuppressWarning包含一个名为value的成员变量,该value的成员变量为String类型的数组,可以取以下几个值:

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

例如,常见的@SuppressWarning(value={"unchecked"})。

3)@Deprecated

用于表示某个程序元素(类、方法等)已过时。如果使用被@Deprecated修饰的类或方法等,编译器会发出警告。

除了Java语言原生自带的这几个注释之外,还可以自定义注释。自定义注释的格式如下:

public @interface 注解名 {定义体}

注解的定义体内只有成员变量,没有成员方法。注解的成员变量在定义中以类似普通Java类中“无形参的方法”的形式来声明,其“方法”名定义了该成员变量的名字,其“返回值”定义了该成员变量的类型。注解的成员变量不需要带访问修饰符,默认情况下都是public的。

注解的成员变量可支持以下几种数据类型:

  1. 所有基本数据类型(int,float,boolean,byte,double,char,long,short等)

  2. String类型

  3. Class类型

  4. 枚举类型(enum)

  5. 注解类型

  6. 成员是以上所有类型的数组类型

可以在定义注解的成员变量时为其指定默认值。指定注解成员变量的默认值使用default关键字。如果注解的成员变量已经指定了默认值,使用该注解时可以不为这些成员变量指定值,而是直接使用其定义的默认值。注解内定义的变量必须要有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态。因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。

注解的成员变量只有public和默认两种访问权限修饰符,

在定义注解时,还可以使用Java语言默认提供的元注解(注解的注解)来修饰你自己定义的注解。Java提供了如下4个元注解:

1)@Retention

@Retention用于指定一个定义的注解可以保留多长时间,也就是指定注解的生命周期。

@Retention包含一个名为value的成员变量,该value成员变量是RetentionPolicy枚举类型。使用@Retention时,必须为其value指定值。value成员变量的值只能是如下3个之一:

  1. RetentionPolicy.SOURCE:表示该注解只保留在源代码中,编译器编译时,直接丢弃这种注解;
  2. RetentionPolicy.CLASS:编译器把该注解记录在.class文件中,但当运行该Java程序时,JVM中不再保留该注解;
  3. RetentionPolicy.RUNTIME:编译器把该注解记录在.class文件中,且当运行该Java程序时,JVM会保留该注解,程序可以通过反射获取该注解的信息。

2)@Target

@Target指定Annotation用于修饰哪些程序元素。@Target也包含一个名为value的成员变量,该value成员变量类型为ElementType[ ],ElementType为枚举类型,值有如下几个:

  1. ElementType.TYPE:能修饰类、接口或枚举类型;
  2. ElementType.FIELD:能修饰成员变量;
  3. ElementType.METHOD:能修饰方法;
  4. ElementType.PARAMETER:能修饰参数;
  5. ElementType.CONSTRUCTOR:能修饰构造器;
  6. ElementType.LOCAL_VARIABLE:能修饰局部变量;
  7. ElementType.ANNOTATION_TYPE:能修饰注解;
  8. ElementType.PACKAGE:能修饰包。

3)@Documented

如果定义一个注解时,使用了@Documented元注解修饰,则在用Javadoc命令生成API文档后,所有使用这个注解修饰的程序元素,将会包含这个注解的说明。

4)@Inherited

@Inherited指定注解具有继承性。例如,如果在一个类上使用了一个带@Inherited元注解的注解,那么在其子类上也默认带了这个注解,即使没有明确指明。

注解说到底,只是给相应的类或方法或变量等特定的域带上相应的属性,但并没有实际做事情(因为注解内是没有包含代码的方法的,只有表示状态的变量)。对应的工具可以读取这些属性,并做出相应的操作。通常的做法是通过反射去读取注解并实时进行操作。但要注意的是,要想使用反射去读取注解,必须将@Retention的值选为RetentionPolicy.RUNTIME。