元注解,是java定义的基本注解,我们可以在很多框架中看到他们的身影,今天我们就刨根问底的看看什么是元注解。一起干饭!
本章主要内容
- 什么是注解,元注解?
- 元注解的用途
- 如何处理注解?
1.什么是注解,元注解?
Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据[1]。
Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容[2]。 当然它也支持自定义Java标注[3]。
Java元注解是可以作用在其他注解的注解:
Java 5 时有4个分别为@Retention、@Documented 、@Target 、@Inherited;
从 Java 7 开始,额外添加了 3 个注解:@SafeVarargs 、@FunctionalInterface 、@Repeatable
2.元注解的用途?
Java 5 提供的4个元注解
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
从 Java 7 开始,额外添加了 3 个注解:
- @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
接下来以@RequestMapping()注解为例来解析元注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
}
2.1 @Retention注解
可以赋值 RetentionPolicy类型,RetentionPolicy定义如下:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* 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,
/**
* 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
}
RetentionPolicy.SOURCE:表明注解会被编译器丢弃,字节码中不会带有注解信息
RetentionPolicy.CLASS:表明注解会被写入字节码文件,且是@Retention的默认值
RetentionPolicy.RUNTIME:表明注解会被写入字节码文件,并且能够被JVM 在运行时获取到,可以通过反射的方式解析到
2.2 @Documented注解
从注释可以看到 @Document注解用途主要是标识类型是否要被收入javadoc
package java.lang.annotation;
/**
* Indicates that annotations with a type are to be documented by javadoc
* and similar tools by default. This type should be used to annotate the
* declarations of types whose annotations affect the use of annotated
* elements by their clients. If a type declaration is annotated with
* Documented, its annotations become part of the public API
* of the annotated elements.
*
* @author Joshua Bloch
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
2.3 @Target注解
标识注解的使用范围,可以赋值为ElementType类型,ElementType定义如下:
package java.lang.annotation;
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
}
以@RequestMapping为例,它的@Target赋值为{ElementType.METHOD, ElementType.TYPE},参考Element注释可以理解@RequestMapping可以用于java的方法定义及Class/Interfac/enum的定义上
2.4 @Inherited注解
标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
使用此注解声明出来的自定义注解,在使用此自定义注解时,如果注解在类上面时,子类会自动继承此注解,否则的话,子类不会继承此注解。这里一定要记住,使用Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。
3.java是如何处理注解的?
- 在类或方法上使用注解
- java编译器编译为.class文件
- 通过反射把.class文件加载到jvm中,生成唯一的Class对象。
- JVM通过反射的方式读取注解信息
- java反射包为注解提供了一个接口java.lang.reflect.AnnotatedElement
- Class类实现了AnnotatedElement接口,在类加载时,会加载Annotation
- 注解都默认继承自java.lang.annotation包下的Annotation接口
任何注解类型都默认继承自java.lang.annotation包下的Annotation接口,表明这是一个注解类型,这是编译器自动帮我们完成的。但是手动继承Annotation没有这个效果,即不会把它当成注解类型。甚至Annotation接口本身也并不意味着它是注解类型。可以简单的理解为:我们可以也只可以通过@interface的方式来定义注解类型,这个注解类型默认会实现Annotation接口。
注解通过设置可以一直保留到运行期,此时VM通过反射的方式读取注解信息。由上面的介绍可知,注解是解释代码的代码,它必须存在于特定的代码元素之上,可以是类,可以是方法,可以是字段等等。
为了更好的在运行时解析这些代码元素上的注解,java在反射包下为它们提供了一个接口java.lang.reflect.AnnotatedElement
不要以为每天把功能完成了就行了,这种思想是要不得的,互勉~!若文章对您有用,请点赞支持哦。
网友评论