一 概述
Java语言中的类,方法,变量,参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取标注内容。在编译生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以标注内容,在运行时可以获取到标注内容。
二 注解的分类
注解按照运行机制分类可以分为:源码注解,编译时注解,运行时注解。
- 源码注解:注解只在源码中存在,编译成.class文件就不存在了。
- 编译时注解:注解在源码和.class文件中均存在。
- 运行时注解:在运行阶段还会继续起作用,甚至会影响运行的逻辑。
此外:注解中存在自己的注解,即元注解。
@Override,@Deprecated,@Suppresswarnings是在java.lang包中的内置的注解:
- @Override:检查该方法是否是重写方法。如果发现其父类或者是引用的接口并没有该方法时,会报编译错误。
- @Deprecated:标记已过时的方法,即不再使用的方法,如果继续使用该方法时,会报编译错误。
- @Suppresswarnings:指编译器去忽略注解中声明的警告。
Java7版本在java.lang包下添加了@SafeVaragrs使得java7开始支持,忽略使用参数为泛型变量的方法或构造函数调用产生的警告。
Java8版本中增加了支持和标识匿名函数或者函数式接口的注解——@FunctionalInterface,以及支持和标识某注解可以在同一生声明上使用多次的注解——@Repeatable(java.lang.annotation包中)。
三 常见的元注解
元注解是一些标注注解的注解,他们都在java.lang.annotation包中。
- @Target({ElementType.METHOD,ElementType.TYPE}):标记这个注解的类别,作用范围。
- @Retention:标记这个注解是那种类型,是源码注解,编译时注解还是运行时注解。即知识保留在源码中,编入class文件中,或者是在运行时通过反射机制可以访问。
- @Inherited:标记这个注解是继承于哪个注解类(默认是没有继承任何子类)。
- @Documented:标记这个注解是否包含在用户文档中。
四 Annotation的重要组成
Java Annotation类中存在着重要的组成,其中Annotation.java,ElementType.java,RetentionPolicy.java就是非常重要的主干类。
Annotation.java源码
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
Annotation只是一个接口,每个Annotation都会同一个RetentionPolicay关联,同时与一个或者多个ElementType进行关联。
ElementType.java源码
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
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
ElementType是Enum枚举类型,用来指定Annotation的类型,也就意味着它将指明Annotation的用途。
RetentionPolicy.java源码
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE, //Annotation信息只是存在于源码中,不会保留在编译后的.class文件中
/**
* 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, //Annotation信息会保存在源码中,同时也会保留在编译后的.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.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME //Annotation信息存在于class文件中,并且可以由JVM读取
}
RetentionPolicy是Enum枚举类型,它用来指定Annotation的策略,即不同的RetentionPolicy类型的Annotation的作用域不同。如注解@Override,当它修饰一个方法时,就意味着该方法覆盖父类的方法,并且在编译期间会进行语法检查,编译处理完成后就没有任何作用了。
五 Java中自带的注解
@Interface
使用@Interface定义注解,则说明它实现了java.lang.annotation.Annotation接口,即注解为一个Annotation。定义注解时,即Annotation时,@interface是必须的。
值得注意的是它并非我们通常用implemented实现接口的接口不同,Annotation接口是由编译器来实现细节的,同时通过@interface定义注解之后,该注解不能继承其他的注解或者接口。
@Documented
类和方法的Annotation在缺省的情况下,不会出现在javadoc中,当我们使用了@Documented修饰该Annotation之后,则表示它可以出现在javadoc中。
@Target
它用来指定Annotation的类型属性,其中ElementType.TYPE则是指明该注解用来修饰"类,接口(包括注释类型)或者枚举声明"的注解。
@Target在注解中可以理解为可有可无,若有@Target,则该Annotation只能用于它所指定的地方;若没有@Target,则该Annotation可以用于任何地方。
@Retention(RetentionPolicy.RUNTIME)
RetentionPolicy是Annotation的策略属性,而@Rentention的作用,就是指定Annotation的策略属性。定义 Annotation 时,@Retention 可有可无,若没有 @Retention,则默认是 RetentionPolicy.CLASS。