AnnotatedElement
正在JVM中运行的程序里被注解的结构,它分为两类声明注解(声明在元素上:类、方法、字段)、类型注解(方法参数@qualifiler、返回值类型@Nullable)。字节码中有属性, 这里的“属性”指的是 Java 类文件(.class 文件)格式中的一种结构,用于存储元数据。它和我们常说的 Java 类的“属性/字段”不是一回事。你可以把它理解为.class 文件里的一张表格或一个列表
RuntimeVisibleAnnotations: 存储作用于类、方法或字段上的运行时可见的注解。RuntimeVisibleParameterAnnotations: 存储方法参数上的运行时可见的注解。RuntimeVisibleTypeAnnotations: 存储类型用法(如泛型、类型转换、继承等)上的运行时可见的注解(Java 8+)。
public interface AnnotatedElement {
Annotation[] getDeclaredAnnotations();
}
注解存在状态
- 直接存在:注解直接存在于元素上,并且运行时可见,也就是要有元注解
@Retention(RetentionPolicy.RUNTIME) - 间接存在:将注解作为数组,装入另一个注解(容器注解),实现重复注解。这样容器注解当然是直接注解,容器内的注解就是间接注解。可重复注解
//将该注解标记为可重复
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(ActionContainer.class)
public @interface Action {
String value();
}
//定义一个容器注解,来存储重复注解。其实它就是一个普通注解,只是它的值是一个注解
//数组,这也时java8之前实现重复注解的方式。@Resources实现重复@Resource
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionContainer {
Action [] value();
}
//这样就实现了可重复注解
@Action("上课")
@Action("下课")
public class Element {
}
//没有@Repeatable时,java8之前。新的注解出现,只是让可重复注解更明了,本质没变
//但无法直接获取内部注解,只能遍历value。如果加了@Repeatable,可以直接通过
//Element.class.getAnnotationsByType(Action.class)获取这两个间接注解
@ActionContainer({@Action("上课"),@Action("下课")})
public class Element {
}
- 存在:直接注解,或者继承注解。,只有容器注解和可重复注解都被明确标记了
@Inherited,可重复注解才会被继承。只标记容器注解,只能获取容器注解。
//如果一个注解有@Inherited元注解,那它注解的元素子类可以继承该注解
public class ChildElement extends Element{
}
//获取直接注解,如果是可重复注解,此时获取的是它的容器注解
Annotation[] annotations = Element.class.getDeclaredAnnotations();
//获取间接注解
Action [] myAnnotations = Element.class.getAnnotationsByType(Action.class);
//获取存在注解:直接注解和继承注解。
Annotation[] childannotations = ChildElement.class.getAnnotations();
//通过继承类获取继承来的间接注解(容器注解、可重复注解都需要标记@Inherited)
Action [] mychildAnnotations = ChildElement.class.getAnnotationsByType(Action.class);
- 关联注解:关联的注解包括直接存在和间接存在的注解,以及通过继承得到的注解
本质
注解是运行时数据区的属性,每个class通过native方法getRawAnnotations获取它的原始注解,解析之后封装到注解数据
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement,
TypeDescriptor.OfField<Class<?>>,
Constable {
...
@Override
public Annotation[] getDeclaredAnnotations() {
return AnnotationParser.toArray(annotationData().declaredAnnotations);
}
...
private transient volatile AnnotationData annotationData;
private AnnotationData annotationData() {
while (true) { // retry loop
AnnotationData annotationData = this.annotationData;
int classRedefinedCount = this.classRedefinedCount;
if (annotationData != null &&
annotationData.redefinedCount == classRedefinedCount) {
return annotationData;
}
// null or stale annotationData -> optimistically create new instance
AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);
// try to install it
if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {
// successfully installed new AnnotationData
return newAnnotationData;
}
}
}
private AnnotationData createAnnotationData(int classRedefinedCount) {
Map<Class<? extends Annotation>, Annotation> declaredAnnotations =
AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this);
..
}
...
// Annotations handling
native byte[] getRawAnnotations();
// Since 1.8
native byte[] getRawTypeAnnotations();