考虑以下代码:
A.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface A{}
C.java:
import java.util.*;
@A public class C {
public static void main(String[] args){
System.out.println(Arrays.toString(C.class.getAnnotations()));
}
}
编译和运行按预期工作:
$ javac *.java
$ java -cp . C
[@A()]
但是再考虑一下:
$ rm A.class
$ java -cp . C
[]
我预计它会抛出 ClassNotFoundException
,因为缺少 @A
。但相反,它会默默地删除注释。
这种行为是否记录在 JLS 中的某个地方,还是 Sun 的 JVM 的怪癖?这样做的理由是什么?
对于 javax.annotation.Nonnull
之类的东西似乎很方便(无论如何,它似乎应该是 @Retention(CLASS)
),但对于许多其他注释似乎它可能会导致运行时发生各种不好的事情。
最佳答案
在 JSR-175(注解)的早期公共(public)草案中,讨论了编译器和运行时是否应该忽略未知注解,以便在注解的使用和声明之间提供更松散的耦合。一个具体的例子是在 EJB 上使用应用程序服务器特定的注释来控制部署配置。如果同一个 bean 应该部署在不同的应用服务器上,如果运行时简单地忽略未知注解而不是引发 NoClassDefFoundError 会很方便。
即使措辞有点模糊,我假设您看到的行为在 JLS 13.5.7 中指定。 :“......删除注释对Java编程语言中程序的二进制表示的正确链接没有影响。”我将此解释为好像注释已删除(在运行时不可用),程序仍应链接并运行,这意味着在通过反射访问时会简单地忽略未知注释。
Sun 的 JDK 5 的第一个版本没有正确实现这一点,但在 1.5.0_06 中已修复。你可以找到相关的bug 6322301在错误数据库中,但它没有指向任何规范,除了声称“根据 JSR-175 规范引导,getAnnotations 必须忽略未知注释”。
关于java - 为什么缺少注释不会在运行时导致 ClassNotFoundException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3567413/