2010-08-25 90 views
76

考虑下面的代码:为什么在运行时没有缺少注释会导致ClassNotFoundException?

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

回答

81

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

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

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

32

引述JLS:

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

的注释类型 annotation.Retention用于选择上述可能性中 。如果 注释的对应一种类型的T, 和T具有 对应于annotation.Retention, 则(甲基)注释米:

  • 若m具有元件,其值是annotation.RetentionPolicy .SOURCE, 那么Java编译器必须确保 a不存在于二进制 表示类或 接口中出现。
  • 若m具有元件,其值是annotation.RetentionPolicy.CLASS,或 annotation.RetentionPolicy.RUNTIME一个 Java编译器必须确保被 表示在类或 接口的二进制 表示,其中一个出现,除非m 注释了一个局部变量 声明。在本地 变量声明中的注释永远不会保留在二进制表示中的 。

如果T不具有(甲基)注释 米对应于 annotation.Retention,然后一个Java编译器 必须对待T作为如果它 具有这样的元注释米与 元素的值为 annotation.RetentionPolicy.CLASS。

所以RetentionPolicy.RUNTIME确保注释被编译成二进制,但在二进制注释不必在运行时使用

-1

注释对代码的操作没有直接影响他们注释。
但是,通过使用@Retention(RetentionPolicy.RUNTIME),注释在运行时变为可用。

现在,我的猜测是@Retention不可用,因此被忽略。这意味着其他注释在运行时不可用。
没有例外,因为默认情况下注释被忽略。他们只考虑@Retention的存在。

也许如果你让舒尔@Retention可用,将会有投诉。 (对此不确定)

+5

@Retention在java.lang.annotation中 - 它怎么可能不可用? – 2010-08-25 20:05:35

7

如果您确实有读取@A并执行某些操作的代码,则代码对类A具有依赖性,并且会抛出ClassNotFoundException。

如果不是,即没有代码特别关注@A,那么@A并不是真的很重要。

相关问题