[英]Recursive usage of @Retention annotation , how is it possible?
在java中的@Retention注释的源代码中, @ Rettention在其定义中使用,如此可能。
即使RetentionPolicy设置为RUNTIME ,那么如何在它未准备好运行之前执行它。
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
这不是真正的递归 。 它只不过是对“后来”后面的类分别接口的前向引用。 Java允许使用前向引用。 对此有各种限制(请参阅Java语言规范,例如第8.3.2.2节) - 但这些限制都不适用于此。
除此之外:请记住,这里没有特殊的编译步骤。 编译器只是为Retention接口创建一个普通的类文件。 但那时:编译器很可能拥有关于此接口的硬编码知识。 如果使用RetentionPolicy.SOURCE ,编译器将从编译的类文件中排除注释。 这意味着编译器必须进行某种检查(以确定是否注释了某些内容并启用了SOURCE策略)。
换句话说:编译器可能包含类似的内容
if (x instaceof Retention) ...
并且此代码存在于编译器中。 编译其他注释时,上述工作正常,但在编译Retention接口本身时也可以正常工作。
但关键信息是:没有递归,只是一个前向引用。 稍后定义使用的东西。
它不需要Retention
类。 源代码首先转换为AST。 它只需要Retention
的qualifield名称来获取注释值。 这是OpenJDK的代码
按类名定义Retention
:
// com.sun.tools.javac.code.Symtab
protected Symtab(Context context) throws CompletionFailure {
...
retentionType = enterClass("java.lang.annotation.Retention");
...
}
使用com.sun.tools.javac.code.Type retentionType
从AST获取RetentionPolicy
(第4行syms.retentionType.tsym
):
// com.sun.tools.javac.code.Types
public RetentionPolicy getRetention(Attribute.Compound a) {
RetentionPolicy vis = RetentionPolicy.CLASS; // the default
Attribute.Compound c = a.type.tsym.attribute(syms.retentionType.tsym);
if (c != null) {
Attribute value = c.member(names.value);
if (value != null && value instanceof Attribute.Enum) {
Name levelName = ((Attribute.Enum)value).value.name;
if (levelName == names.SOURCE) vis = RetentionPolicy.SOURCE;
else if (levelName == names.CLASS) vis = RetentionPolicy.CLASS;
else if (levelName == names.RUNTIME) vis = RetentionPolicy.RUNTIME;
else ;// /* fail soft */ throw new AssertionError(levelName);
}
}
return vis;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.