2010-08-25 8 views
76

Betrachten Sie den folgenden Code ein:Warum verursacht eine fehlende Anmerkung während der Laufzeit keine 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())); 
     } 
} 

Kompilieren und Ausführen funktioniert wie erwartet:

$ javac *.java 
$ java -cp . C 
[@A()] 

Aber dann prüfen dies:

$ rm A.class 
$ java -cp . C 
[] 

Ich hätte erwartet, dass es eine ClassNotFoundException werfen, da @A fehlt. Stattdessen wird die Annotation stillgelegt.

Ist dieses Verhalten irgendwo in der JLS dokumentiert, oder ist es eine Eigenart von Suns JVM? Was ist der Grund dafür?

Es scheint praktisch für Dinge wie javax.annotation.Nonnull (was scheint, als hätte es @Retention(CLASS) sowieso sein sollte), aber für viele andere Anmerkungen scheint es könnte dazu führen, dass verschiedene schlechte Dinge zur Laufzeit passieren.

Antwort

81

In den früheren öffentlichen Entwürfen für JSR-175 (Annotationen) wurde diskutiert, ob der Compiler und die Laufzeit unbekannte Annotationen ignorieren sollten, um eine lockere Kopplung zwischen der Verwendung und der Deklaration von Annotationen zu ermöglichen. Ein spezifisches Beispiel war die Verwendung anwendungsserverspezifischer Anmerkungen in einem EJB, um die Bereitstellungskonfiguration zu steuern. Wenn dieselbe Bean auf einem anderen Anwendungsserver implementiert werden sollte, wäre es praktisch, wenn die Laufzeitumgebung einfach die unbekannten Annotationen ignorierte, anstatt einen NoClassDefFoundError auszulösen.

Auch wenn der Wortlaut etwas vage ist, nehme ich an, dass das Verhalten, das Sie sehen, in JLS 13.5.7 spezifiziert ist: "... das Entfernen von Anmerkungen hat keinen Einfluss auf die korrekte Verknüpfung der binären Darstellungen von Programmen in die Java-Programmiersprache. " Ich interpretiere das so, als ob Annotationen entfernt werden (zur Laufzeit nicht verfügbar), das Programm sollte trotzdem verlinken und laufen und das bedeutet, dass die unbekannten Annotationen einfach ignoriert werden, wenn durch Reflektion zugegriffen wird.

Die erste Version von Suns JDK 5 hat dies nicht korrekt implementiert, aber es wurde in 1.5.0_06 behoben. Sie können den relevanten Fehler 6322301 in der Fehlerdatenbank finden, aber es zeigt keine Spezifikationen außer der Behauptung, dass laut dem JSR-175 spec lead, unbekannte Anmerkungen von getAnnotations ignoriert werden müssen.

32

das JLS Zitiert:

9.6.1.2 Retention Annotations kann nur in dem Quellcode enthalten sein, oder sie können in der Binärform einer Klasse oder Schnittstelle vorhanden sein. Eine Anmerkung , die in der binären möglicherweise vorhanden ist oder möglicherweise nicht zur Laufzeit über die reflektierenden Bibliotheken der Java -Plattform zur Verfügung.

Der Annotationstyp annotation.Retention wird verwendet, um unter den obigen Möglichkeiten zu wählen. Wenn ein Annotation a entspricht einem Typ T, T und hat eine (Meta-) Anmerkung m, die zu annotation.Retention entspricht, dann:

  • Wenn M ein Element ist, dessen Wert hat annotation.RetentionPolicy .SOURCE, dann muss ein Java-Compiler sicherstellen, dass a nicht in der binären Darstellung der Klasse oder Schnittstelle, in der ein erscheint, vorhanden ist.
  • Wenn m ein Element, dessen Wert annotation.RetentionPolicy.CLASS oder annotation.RetentionPolicy.RUNTIME ein Java-Compiler muss sicherstellen, dass ein in der binären Darstellung der Klasse oder Schnittstelle dargestellt wird, in der A erscheint , es sei denn, m kennzeichnet eine lokale Variable Deklaration. Eine Annotation zu einer lokalen Variablendeklaration wird nie in der binären Darstellung beibehalten.

Wenn T kein (Meta-) haben Anmerkung m, die annotation.Retention entspricht, dann ist ein Java Compiler muss T behandeln, als ob es nicht so eine Meta-Annotation m mit einem Element mit dem Wert annotation.RetentionPolicy.CLASS.

So wird sichergestellt, dass RetentionPolicy.RUNTIME die Anmerkung in das binäre kompiliert wird, aber eine Anmerkung in der binären nicht über

-1

Anmerkungen haben keine direkte Auswirkung auf den Betrieb des Codes zur Laufzeit zur Verfügung stehen sie kommentieren.
Mithilfe von @Retention(RetentionPolicy.RUNTIME) werden die Anmerkungen jedoch zur Laufzeit verfügbar.

Nun, meine Vermutung ist, dass @Retention nicht verfügbar ist und daher ignoriert. Dies bedeutet, dass die anderen Anmerkungen zur Laufzeit nicht verfügbar gemacht werden.
Es gibt keine Ausnahme, da Annotationen standardmäßig ignoriert werden. Nur in Gegenwart von @Retention werden sie berücksichtigt.

Wahrscheinlich, wenn Sie shure @Retention zur Verfügung stellen, wird es eine Beschwerde geben. (nicht sicher darüber)

+5

@Retention ist in java.lang.annotation - wie könnte es nicht verfügbar sein? –

7

Wenn Sie tatsächlich Code haben, der @A liest und etwas damit macht, hat der Code eine Abhängigkeit von Klasse A und wird ClassNotFoundException auslösen.

Wenn nicht, d. H. Kein Code kümmert sich speziell um @A, dann ist es wohl möglich, dass @A nicht wirklich wichtig ist.

Verwandte Themen