Im Jahr 2005, mit der Einführung von Java 5, lernten wir neue Entitäten namens Annotationen kennen.

Anmerkungen sind eine spezielle Form syntaktischer Metadaten, die im Code deklariert werden können. Sie werden verwendet, um Code beim Kompilieren oder zur Laufzeit zu analysieren. Sie können sich eine Anmerkung als Beschriftung, Tag oder Compiler-Hinweis vorstellen.

Sie sind wahrscheinlich schon einmal auf Anmerkungen gestoßen. Wenn wir beispielsweise eine Methode der übergeordneten Klasse überschreiben, schreiben wir @Override vor der Methode selbst. Diese Anmerkung gibt an, dass die Methode des übergeordneten Elements in der untergeordneten Klasse überschrieben wird.

Syntax:


@Override
public int hashCode() {
      return super.hashCode();
}

Ich möchte gleich darauf hinweisen, dass Anmerkungen nicht nur für Methoden gelten. Sie werden mit Paketen, Klassen, Methoden, Feldern und Parametern verwendet.

Um zu verstehen, wie Anmerkungen funktionieren, machen wir uns zunächst mit dem Konzept einer Markierungsschnittstelle vertraut. Seit dem Aufkommen von Java brauchten Entwickler immer eine Möglichkeit, Klassen zu markieren, um bestimmte Aktionen auf ihnen auszuführen.

Vor Java 5 verwendeten sie eine Schnittstelle, die nicht das tat, was wir von Schnittstellen erwarten. Es gab keine Methoden und keinen Vertrag. Es hat einfach eine Klasse in gewisser Weise als etwas Besonderes markiert.

Eine solche Schnittstelle wurde Markerschnittstelle genannt. Der Name lässt vermuten, dass der Zweck darin besteht, Klassen für die JVM, den Compiler oder eine Bibliothek zu kennzeichnen. Einige Markierungsschnittstellen, wie z. B. Serializable , bleiben bestehen. Mit dieser Markierungsschnittstelle können wir angeben, dass Instanzen einer Klasse serialisiert werden können.

Wie wir gesehen haben, bleiben Markierungsschnittstellen auch nach der Einführung von Anmerkungen bestehen.

Anmerkungen versus Markierungsschnittstellen:


@MyAnnotation
public class MyClass {}

public class MyClass implements MarkerInterface {}

Beide Ansätze verfolgen das gleiche Ziel, es gibt jedoch einen deutlichen Unterschied in der Umsetzung. Betrachten Sie beispielsweise eine Schnittstelle und eine Annotation, die angibt, dass eine Klasse zu einem bestimmten Typ gehört.

Wenn wir eine Schnittstelle verwenden, markieren wir die Klasse. Wenn wir es falsch verwenden und ein Fehler auftritt, entdecken wir das Problem beim Kompilieren und das Programm wird nicht ausgeführt.

Bei Annotationen ist nicht alles so einfach: Hier wird der Fehler zur Laufzeit erkannt, was bedeutet, dass das Programm startet, aber, wenig überraschend, nicht beendet wird.

Beachten Sie, dass, wenn wir eine Klasse für die zukünftige Verwendung markieren müssen, ihre Instanzen an eine bestimmte Methode übergeben werden müssen:


public class MyInteger implements Sum {}
interface Sum {};

public static void main(String[] args) throws IOException {
        increase(new MyInteger());
}
 
public static void increase(Sum count) {
        // TODO
}

Eine Marker-Schnittstelle funktioniert hier am besten.

Es ist am besten, Anmerkungen zu verwenden, wenn wir mehr benötigen, beispielsweise die Parameter, die Anmerkungen unterstützen.

Schauen wir uns die Standardanmerkungen im JDK an:

Anmerkung Beschreibung Beispiel
@Override Gibt an, dass eine Methode die Methode einer Oberklasse überschreibt oder eine Methode einer abstrakten Klasse oder Schnittstelle implementiert.

@Override
public int hashCode() {
        return super.hashCode();
}
@Veraltet Markiert Code als veraltet.

@Deprecated
public abstract void method();
@SuppressWarnings Deaktiviert Compilerwarnungen für das mit Anmerkungen versehene Element. Beachten Sie, dass, wenn Sie mehrere Kategorien von Warnungen deaktivieren müssen, diese in geschweifte Klammern eingeschlossen werden müssen, zum Beispiel @SuppressWarnings({"unchecked", "cast"}) .

public class DocumentsFolder {
   private List documents;

   @SuppressWarnings("unchecked")
public void addDocument(String document) {
            documents.add(document);
   }
}

In diesem Beispiel versuchen wir, etwas zu einer Liste hinzuzufügen, die keinen definierten Typ (einen generischen Typ) hat. Der Compiler wird uns hierüber warnen. Das ist sehr nützlich, aber manchmal gibt es zu viele „Warnungen“ und sie können laut sein. Sie können diese Methodenanmerkung verwenden und einen Typ einer Compilerwarnung als Argument angeben. Es gibt viele Markierungen, also machen Sie sich keine Sorgen, sich alle zu merken – IDEA sagt Ihnen normalerweise, welche Sie hinzufügen müssen.

Ein weiteres Beispiel mit mehreren Argumenten:


@SuppressWarnings({"unchecked", "deprecated"})