@Retention注释的递归使用,它怎么可能?

在java中@Retention注解的源代码中, @Retention被用在它自己的定义中,这是可能的。

即使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节) - 但这些限制都不适用于此。

除此之外:请记住,这里没有特别的汇编步骤。 编译器只是为保留接口创建一个普通的类文件。 但是,然后:编译器很可能具有关于此接口的硬编码知识。 如果使用RetentionPolicy.SOURCE,则编译器将从编译的类文件中排除注释。 这意味着编译器必须进行某种检查(以确定是否注释了某些内容并启用了SOURCE策略)。

换句话说:编译器可能包含类似的东西

if (x instaceof 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(第4行syms.retentionType.tsym )获取RetentionPolicy

// 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;
}
链接地址: http://www.djcxy.com/p/40879.html

上一篇: Recursive usage of @Retention annotation , how is it possible?

下一篇: Running a Perl script from crontab when you use Perlbrew