Java 为什么';缺少注释是否会在运行时导致ClassNotFoundException?

Java 为什么';缺少注释是否会在运行时导致ClassNotFoundException?,java,annotations,Java,Annotations,考虑以下代码: 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){

考虑以下代码:

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)
)这样的东西来说,它似乎很方便,但是对于许多其他注释来说,它似乎会在运行时导致各种不好的事情发生。

引用JLS:

9.6.1.2保留注释只能出现在源代码中,或者 它们可能以二进制形式出现 类或接口的注释 存在于二进制文件中的可能或 在运行时可能无法通过 Java的反射库 平台。

注释类型 注释。保留用于选择 在上述可能性中。如果 注释a对应于类型T, T有一个(元)注释m 对应于注释。保留, 然后:

  • 如果m有一个值为annotation.RetentionPolicy.SOURCE的元素, 然后Java编译器必须确保 二进制文件中不存在a 类或类的表示 在其中显示的界面
  • 如果m有一个值为annotation.RetentionPolicy.CLASS的元素,或 annotation.RetentionPolicy.RUNTIME a Java编译器必须确保 以二进制表示 类或类的表示 显示a的接口,除非m 注释局部变量 宣言。局部图形上的注释 变量声明永远不会被保留 在二进制表示中
如果T没有(元)注释 对应于 保留,然后是Java 编译器必须像对待T一样对待它 有这样一个带有 值为的元素 annotation.RetentionPolicy.CLASS

因此RetentionPolicy.RUNTIME确保注释被编译成二进制文件,但二进制文件中的注释不必在运行时可用,引用JLS:

9.6.1.2保留注释只能出现在源代码中,或者 它们可能以二进制形式出现 类或接口的注释 存在于二进制文件中的可能或 在运行时可能无法通过 Java的反射库 平台。

注释类型 注释。保留用于选择 在上述可能性中。如果 注释a对应于类型T, T有一个(元)注释m 对应于注释。保留, 然后:

  • 如果m有一个值为annotation.RetentionPolicy.SOURCE的元素, 然后Java编译器必须确保 二进制文件中不存在a 类或类的表示 在其中显示的界面
  • 如果m有一个值为annotation.RetentionPolicy.CLASS的元素,或 annotation.RetentionPolicy.RUNTIME a Java编译器必须确保 以二进制表示 类或类的表示 显示a的接口,除非m 注释局部变量 宣言。局部图形上的注释 变量声明永远不会被保留 在二进制表示中
如果T没有(元)注释 对应于 保留,然后是Java 编译器必须像对待T一样对待它 有这样一个带有 值为的元素 annotation.RetentionPolicy.CLASS


因此,RetentionPolicy.RUNTIME确保注释被编译成二进制文件,但二进制文件中的注释不必在运行时可用

在早期的JSR-175(注释)公共草案中,讨论了编译器和运行时是否应忽略未知注释,在注释的使用和声明之间提供更松散的耦合。一个具体的例子是在EJB上使用应用服务器特定的注释来控制部署配置。如果相同的bean应该部署在不同的应用程序服务器上,那么如果运行时只是忽略未知的注释而不是引发NoClassDefFoundError,这会很方便

即使措辞有点模糊,我假设您看到的行为是在:“……删除注释对Java编程语言中程序的二进制表示的正确链接没有影响。”我将其解释为注释被删除(在运行时不可用),程序应该仍然链接并运行,这意味着当通过反射访问时,未知注释将被忽略


Sun的JDK5的第一个版本没有正确实现这一点,但它在1.5.0_06中得到了修复。您可以在bug数据库中找到相关的bug,但它没有指向任何规范,只是声称“根据JSR-175规范的领导,未知的注释必须被getAnnotations忽略”。

在早期的JSR-175(注释)公共草案中,讨论了编译器和运行时是否应该忽略未知注释,以便在注释的使用和声明之间提供更松散的耦合。一个具体的例子是在EJB上使用应用服务器特定的注释来控制部署配置。如果相同的bean应该部署在不同的应用程序服务器上,那么如果运行时只是忽略未知的注释而不是引发NoClassDefFoundError,这会很方便

即使措辞有点模糊,我也认为b