2010-08-25 92 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並不是真的很重要。

相關問題