Java注解
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 注解可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留注解内容,在运行时可以获取到注解内容 。 当然它也支持自定义 Java 注解。
内置注解
java中预定义的注解,比如@Override
(用在方法上,表示重写该父类的方法), @Deprecated
(用在方法之前,表示该方法已经过期,不建议再继续使用,但是仍然有效,只不过可能在后面的版本删除)。
@Override
@Override
是用在方法上的,用来表示子类方法重写父类方法。
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。
元注解
用来注解注解的注解。
Java 元注解有四个(JDK1.5时)
- @Retention:注解的保留位置
- @Target:注解的作用目标
- @Document:说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
Annotation 组成部分
java Annotation 的组成中,有 3 个非常重要的主干类。它们分别是:
Annotation.java
、ElementType.java
、RetentionPolicy.java
、
说明:
- Annotation 就是个接口。
“每 1 个 Annotation” 都与 “1 个 RetentionPolicy” 关联,并且与 “1~n 个 ElementType” 关联。可以通俗的理解为:每 1 个 Annotation 对象,都会有唯一的 RetentionPolicy 属性;至于 ElementType 属性,则有 1~n 个。 - ElementType 是 Enum 枚举类型,它用来指定 Annotation 的类型。
“每 1 个 Annotation” 都与 “1~n 个 ElementType” 关联。当 Annotation 与某个 ElementType 关联时,就意味着:Annotation有了某种用途。例如,若一个 Annotation 对象是 METHOD 类型,则该 Annotation 只能用来修饰方法。 - RetentionPolicy 是 Enum 枚举类型,它用来指定 Annotation 的策略。通俗点说,就是不同 RetentionPolicy 类型的 Annotation 的作用域不同。
“每 1 个 Annotation” 都与 “1 个 RetentionPolicy” 关联。- 若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该 Annotation 就没用了。 例如," @Override" 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,“@Override” 就没有任何作用了。
- 若 Annotation 的类型为 CLASS,则意味着:编译器将 Annotation 存储于类对应的 .class 文件中,它是 Annotation 的默认行为。
- 若 Annotation 的类型为 RUNTIME,则意味着:编译器将 Annotation 存储于 class 文件中,并且可由JVM读入。
只需要记住"每 1 个 Annotation" 都与 “1 个 RetentionPolicy” 关联,并且与 “1~n 个 ElementType” 关联。
注解语法
以@Deprecated
为例做下解释。
package java.lang;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PACKAGE, ElementType.MODULE, ElementType.PARAMETER, ElementType.TYPE})
public @interface Deprecated {
String since() default "";
boolean forRemoval() default false;
}
@interface
使用 @interface
定义注解时,意味着它实现了 java.lang.annotation.Annotation
接口,即该注解就是一个Annotation。定义注解时,@interface
是必须的。
它和我们通常的 implemented 实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过 @interface 定义注解后,该注解不能继承其他的注解或接口。
@Documented
类和方法的 Annotation 在缺省情况下是不出现在 javadoc 中的。如果使用 @Documented 修饰该 Annotation,则表示它可以出现在 javadoc 中。
定义 Annotation 时,@Documented 可有可无;若没有定义,则 Annotation 不会出现在 javadoc 中。
@Target(ElementType.TYPE…)
ElementType 是 Annotation 的类型属性。而 @Target 的作用,就是来指定 Annotation 的类型属性。
@Target(ElementType.TYPE) 的意思就是指定该 Annotation 的类型是 ElementType.TYPE。这就意味着@Deprecated是来修饰"字段声明、构造方法…等"的注解。
ElementType | 说明 |
---|---|
TYPE | 类、接口(包括注释类型)或枚举声明 |
FIELD | 字段声明(包括枚举常量) |
METHOD | 方法声明 |
PARAMETER | 参数声明 |
CONSTRUCTOR | 构造方法声明 |
LOCAL_VARIABLE | 局部变量声明 |
ANNOTATION_TYPE | 注释类型声明 |
PACKAGE | 包声明 |
@Retention(RetentionPolicy.RUNTIME)
RetentionPolicy 是 Annotation 的策略属性,而 @Retention 的作用,就是指定 Annotation 的策略属性。
@Retention(RetentionPolicy.RUNTIME) 的意思就是指定该 Annotation 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将该 Annotation 信息保留在 .class 文件中,并且能被虚拟机读取。
定义 Annotation 时,@Retention 可有可无。若没有 @Retention,则默认是 RetentionPolicy.CLASS。
RetentionPolicy | 说明 |
---|---|
SOURCE | 信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 |
CLASS | 编译器将Annotation存储于类对应的.class文件中。默认行为 |
RUNTIME | 编译器将Annotation存储于class文件中,并且可由JVM读入 |
获取注释内容
1.先利用反射获取Class对象
2.使用Class.getAnnotations()获取类上的所有注解内容
3.使用Class.getDeclaredField(“XX”)获取Class对象的特定内容的field对象,然后使用field.getAnnotation(XXX.class),获取到注解的内容
TODO 具体例子
代码源码Annotation
-
@Override
重写方法@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
-
Deprecated
弃用声明@Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }
-
@Retention:注解的保留位置
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }//@since 1.5
-
@Target:注解的作用目标
@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(); }//@since 1.5
-
@Document:说明该注解将被包含在javadoc中
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }//@since 1.5
-
@Inherited:说明子类可以继承父类中的该注解
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }//@since 1.5
-
@Repeatable 标识某注解可以在同一个声明上使用多次
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Repeatable { /** * Indicates the <em>containing annotation type</em> for the * repeatable annotation type. * @return the containing annotation type */ Class<? extends Annotation> value(); }//@since 1.8
代码源码Java
Annotation.java
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
ElementType.java
package java.lang.annotation;
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
PARAMETER, /* 参数声明 */
CONSTRUCTOR, /* 构造方法声明 */
LOCAL_VARIABLE, /* 局部变量声明 */
ANNOTATION_TYPE, /* 注释类型声明 */
PACKAGE /* 包声明 */
}
RetentionPolicy.java
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */
CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */
RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}
RetentionPolicy | 说明 |
---|---|
SOURCE | 信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 |
CLASS | 编译器将Annotation存储于类对应的.class文件中。默认行为 |
RUNTIME | 编译器将Annotation存储于class文件中,并且可由JVM读入 |
注释与注解
Java 注释(Java Doc Comment)与注解(Annotation)
- Java 语言中的类、方法、变量、参数和包等都可以被标注,用来对这些元素进行说明,注释。
- 和 Javadoc(文档注释) 不同,Java 标注可以通过反射获取标注内容。
- 它不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问。
- 注释内容是:不会被编译的内容,只是解释说明。
参考: