类级别注释的定义类加载器是否始终是该类的初始类加载器的父级?

时间:2014-05-02 21:45:14

标签: java classloader

假设以下内容:

@SomeAnnotation
public interface Foo {
}

我想知道SomeAnnotation的定义类加载器是否等于Foo的初始类加载器的父类。

我看过JVMS v8 section 5.3。但我不确定这里适用的是什么。第5.3.4节讨论了加载约束,但它们似乎不适用于注释。

我问的问题是因为这样的代码:

    Class<?> fooClass = //will in some way obtain a reference to class Foo
    fooClass.getAnnotation(SomeAnnotation.class);

将在不同的类加载器存在时失败。我知道我可以使用getAnnotations并在结果数组中搜索类名等于SomeAnnotation的元素。但是我想知道以下内容是否也会起作用:

    Class<?> fooClass = //will in some way obtain a reference to class Foo
    fooClass.getAnnotation((Class<? extends Annotation>) fooClass
            .getClassLoader().loadClass(SomeAnnotation.class.getName()));

1 个答案:

答案 0 :(得分:8)

答案简短:没有

答案很长。

RetentionPolicy.RUNTIME注释仅可通过反射API进行发现。这样做是为了确保注释和带注释的代码之间的松散耦合。根据{{​​3}},getAnnotations()必须跳过未知的注释,这意味着可以使用类加载器无法识别的注释。所讨论的真实Java代码的行为this bug report验证了这种假设。

这种行为有两个含义:

  1. 所有无法识别的注释(例如不在类路径中的注释)变为“隐形”
  2. 为了揭示它们,该类必须由可以访问类型和注释的不同类加载器完全重新加载。
  3. 例如,如果加载somepkg.SomeAnnotationsomeClass不在类路径中,则无效:

    Class<?> someClass = ....
    URL [] classPathWithAnnotations = ....
    
    ClassLoader cl = new URLClassLoader(classPathWithAnnotations);
    Annotation a = someClass.getAnnotation(cl.loadClass("somepkg.SomeAnnotation"));
    // a will be null
    

    但这会:

    Class<?> someClass = ....
    URL [] classPathWithSomeClassAndAnnotations = ....
    
    ClassLoader cl = new URLClassLoader(classPathWithSomeClassAndAnnotations, null);
    Annotation a = cl.loadClass(someClass.getName()).getAnnotation(cl.loadClass("somepkg.SomeAnnotation"));