Wie funktionieren Annotationen wie @Override intern in Java?

90

Kann mir jemand erklären, wie Anmerkungen intern in Java funktionieren?

Ich weiß, wie wir mithilfe der Bibliothek java.lang.annotation in Java benutzerdefinierte Anmerkungen erstellen können. Aber ich verstehe immer noch nicht, wie es intern funktioniert, zum Beispiel die @ Override-Annotation.

Ich wäre sehr dankbar, wenn jemand dies im Detail erklären könnte.

Chirag Dasani
quelle
4
Was meinst du mit "intern arbeiten"? Der Compiler? Die Laufzeit?
Chrylis
3
@chrylis Intern arbeiten bedeutet, dass automatisch festgestellt wird, dass es sich bei dieser Methode um eine Überschreibungsmethode handelt oder dass es sich bei dieser Methode nicht um eine Überschreibungsmethode handelt. Es ist Arbeit an beiden Zeiten. wie Überschreiben Annotation Arbeit in der Kompilierungszeit und Spring Controller Annotation ist Arbeit in der Laufzeit
Chirag Dasani

Antworten:

137

Der erste Hauptunterschied zwischen Annotationstypen besteht darin, ob sie zur Kompilierungszeit verwendet und dann verworfen (wie @Override) oder in die kompilierte Klassendatei gestellt werden und zur Laufzeit verfügbar sind (wie Spring's @Component). Dies wird durch die @ Retention- Richtlinie der Anmerkung bestimmt. Wenn Sie Ihre eigene Anmerkung schreiben, müssen Sie entscheiden, ob die Anmerkung zur Laufzeit (möglicherweise für die automatische Konfiguration) oder nur zur Kompilierungszeit (zur Überprüfung oder Codegenerierung) hilfreich ist.

Beim Kompilieren von Code mit Anmerkungen sieht der Compiler die Anmerkung genauso wie andere Modifikatoren in Quellelementen, wie z. B. Zugriffsmodifikatoren ( public/ private) oder final. Wenn eine Annotation auftritt, wird ein Annotationsprozessor ausgeführt, der einer Plug-In-Klasse ähnelt, die angibt, dass eine bestimmte Annotation interessiert ist. Der Anmerkungsprozessor verwendet im Allgemeinen die Reflection-API, um die zu kompilierenden Elemente zu überprüfen, und kann sie einfach überprüfen, ändern oder neuen zu kompilierenden Code generieren. @Overrideist ein Beispiel für die erste; Es verwendet die Reflection-API, um sicherzustellen, dass eine Übereinstimmung mit der Methodensignatur in einer der Oberklassen gefunden werden kann, und verwendet die Messager, um einen Kompilierungsfehler zu verursachen, wenn dies nicht möglich ist.

Es gibt eine Reihe von Tutorials zum Schreiben von Anmerkungsprozessoren. Hier ist eine nützliche . Sehen Sie sich die Methoden auf der ProcessorSchnittstelle an, um herauszufinden, wie der Compiler einen Annotationsprozessor aufruft. Die Hauptoperation findet in der processMethode statt, die jedes Mal aufgerufen wird, wenn der Compiler ein Element mit einer übereinstimmenden Annotation sieht.

chrylis -vorsichtig optimistisch-
quelle
Danke @chrylis, jetzt sind mir alle meine Zweifel bezüglich der Anmerkung klar.
Chirag Dasani
3
Es wäre schön, uns genau zu zeigen, wie der Annotation-Prozessor von Spring die @Component analysiert und die Klasse in ihren Container
einfügt
@shanyangqu Das ist kein Thema für die Frage, die nicht frühlingsspezifisch ist. Sie können die Postprozessorklassen selbst lesen.
Chrylis
41

Neben den Vorschlägen anderer empfehle ich Ihnen, eine angepasste Anmerkung und deren Prozessor von Grund auf neu zu schreiben, um zu sehen, wie die Anmerkung funktioniert.

In meinem eigenen Beispiel habe ich beispielsweise eine Anmerkung geschrieben, um zu überprüfen, ob Methoden in der Kompilierungszeit überladen sind.

Erstellen Sie zunächst eine Anmerkung mit dem Namen Overload. Diese Anmerkung wird auf die Methode angewendet, daher kommentiere ich sie mit@Target(value=ElementType.METHOD)

package gearon.customAnnotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(value=ElementType.METHOD)
public @interface Overload {

}

Erstellen Sie als Nächstes einen entsprechenden Prozessor, um Elemente zu verarbeiten, die mit einer definierten Anmerkung versehen sind. Bei Methoden, die mit Anmerkungen versehen sind @Overload, muss ihre Signatur mehrmals erscheinen. Oder der Fehler wird gedruckt.

package gearon.customAnnotation;

import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;

@SupportedAnnotationTypes("gearon.customAnnotation.Overload")

public class OverloadProcessor extends AbstractProcessor{

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // TODO Auto-generated method stub
        HashMap<String, Integer> map = new HashMap<String, Integer>();

        for(Element element : roundEnv.getElementsAnnotatedWith(Overload.class)){
            String signature = element.getSimpleName().toString();
            int count = map.containsKey(signature) ? map.get(signature) : 0;
            map.put(signature, ++count);
        }

        for(Entry<String, Integer> entry: map.entrySet()){
            if(entry.getValue() == 1){
                processingEnv.getMessager().printMessage(Kind.ERROR, "The method which signature is " + entry.getKey() +  " has not been overloaded");
            }
        }
        return true;
    }
}

Erstellen @OverloadSie nach dem Packen der Annotation und ihres Prozesses in eine JAR-Datei eine Klasse mit und kompilieren Sie sie mit javac.exe.

import gearon.customAnnotation.Overload;

public class OverloadTest {
    @Overload
    public static void foo(){
    }

    @Overload
    public static void foo(String s){

    }

    @Overload
    public static void nonOverloadedMethod(){

    }
} 

Da nonOverloadedMethod()es nicht wirklich überladen wurde, erhalten wir die Ausgabe wie folgt:

Geben Sie hier die Bildbeschreibung ein

Eugene
quelle
Die obigen Informationen sind sehr gut in Bezug auf JDK6 (+1 dafür), aber wie kann man dasselbe auch mit JDK5 erreichen? Mit JDK6 SupportedAnnotationTypes, AbstractProcessor-Klasse, wurde es einfacher, aber wie ist das gleiche in der Vergangenheit passiert (wie Spring FrameWork 2.5 auf jdk5)? Wie erkennt JVM Annotation-Prozessoren wie class in jdk5? Können Sie bitte eine Anleitung geben, indem Sie die Antwort in Abschnitt 2 bearbeiten (eine für JDK5, aktuelle Version ist für Jdk6 +)?
Prajitgandhi
In deiner Klasse, OverloadProcessor::processwarum ist es so entry.getValue() == 1? Man muss keine Annotation an der übergeordneten Klasse / Schnittstelle hinzufügen, roundEnv.getElementsAnnotatedWith(Overload.class)bekommt also nicht die übergeordnete Klasse / Schnittstelle, oder?
Regen
Ich bin in diesem Teil verwirrt, aber ich denke, Ihre Antwort ist sehr hilfreich.
Regen
@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ Wenn eine Methode als Überladung behandelt wird, sollte in der Klasse mindestens eine andere Methode mit demselben Namen definiert sein.
Eugene
1
@Raining für eine Methode, die "Überladen" sagt, muss sie mehr als einmal in derselben Klasse vorkommen, aber wenn sie "== 1" ist, ist dies ein Fehler.
KrishPrabakar
4

Hier ist @Override: http://www.docjar.com/html/api/java/lang/Override.java.html .

Es gibt nichts Besonderes, das es von einer Anmerkung unterscheidet, die Sie selbst schreiben könnten. Die interessanten Teile befinden sich in den Verbrauchern der Anmerkungen. Für eine Annotation wie @Overridediese wäre dies im Java-Compiler selbst oder in einem statischen Code-Analyse-Tool oder in Ihrer IDE.

Matt Ball
quelle
1
Ich kenne den Quellcode der Override-Annotation. Aber wie es intern funktioniert. Wie kann festgestellt werden, dass diese Methode keine Override-Methode ist oder dass diese Methode Override ist? oder kann ich meine benutzerdefinierte Überschreibungsanmerkung erstellen? und es sollte genau das gleiche Verhalten wie Java Override Annotation funktionieren
Chirag Dasani
3
Wie ich in meiner Antwort sagte, ist das Verhalten nicht Teil der Anmerkung. Die Interpretation liegt in den Dingen, die die Annotation verbrauchen. Aus diesem Grund können Sie praktisch keine eigene benutzerdefinierte Version @Override(oder andere Standardanmerkungen) erstellen, es sei denn, Sie ändern den Verbraucher .
Matt Ball
3

Anmerkungen sind im Grunde nur Markierungen, die vom Compiler oder der Anwendung gelesen werden. Abhängig von ihrer Aufbewahrungsrichtlinie sind sie nur zur Kompilierungszeit verfügbar oder können zur Laufzeit mithilfe von Reflection gelesen werden.

Viele Frameworks verwenden die Laufzeitaufbewahrung, dh sie prüfen reflektierend, ob einige Anmerkungen zu einer Klasse, Methode, einem Feld usw. vorhanden sind, und tun etwas, wenn die Anmerkung vorhanden ist (oder nicht). Darüber hinaus können Mitglieder von Anmerkungen verwendet werden, um weitere Informationen weiterzugeben.

Thomas
quelle
3

Folgen Sie diesem Link . Dies gibt eine genaue Antwort auf Ihr Problem. Wenn wir uns auf Anmerkungen in konzentriert habenJava , wurden Anmerkungen in Java 5 eingeführt und sind nicht spring-spezifisch. Im Allgemeinen können Sie mit Anmerkungen einer Klasse, Methode oder Variablen Metadaten hinzufügen. Eine Annotation kann vom Compiler (z. B. die @ Override-Annotation) oder von einem Framework wie spring (z. B. der @ Component-Annotation) interpretiert werden.

Außerdem füge ich weitere Referenzen hinzu.

  1. http://www.codeproject.com/Articles/272736/Understanding-Annotations-in-Java
  2. http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html
  3. http://www.coderanch.com/how-to/java/AnnotationsExample
Ruchira Gayan Ranaweera
quelle
@LuiggiMendoza Java 1.7 Annotation doc hinzugefügt
Ruchira Gayan Ranaweera
@Ruchira Ich habe alle Links geöffnet, aber ich bin immer noch nicht geklärt, wie es funktioniert. Kannst du mich in Details erklären, die ich als Frühlingsanmerkungen betrachte? Ich kann all die Dinge tun, indem ich Annotation verwende, ohne eine Konfiguration in die Datei spring.xml zu schreiben. Wird die Annotation intern an die XML-Konfiguration gebunden?
Chirag Dasani
@ChiragDasani werfen Sie einen Blick darauf. Dies kann Ihnen helfen, static.springsource.org/spring/docs/3.0.0.M3/reference/html/… und auch diesen SO-Beitrag stackoverflow.com/questions/2798181/…
Ruchira Gayan Ranaweera
0

Sogar ich suchte nach der Antwort auf dieselbe Frage. Der folgende Link lieferte die konsolidierten guten Sachen, um das Innere von Anmerkungen zu erhalten. https://dzone.com/articles/how-annotations-work-java Hoffe, es hilft!

Kusum
quelle