In 2005, met de komst van Java 5, leerden we nieuwe entiteiten kennen die annotaties worden genoemd.

Annotaties zijn een speciale vorm van syntactische metadata die in code kunnen worden gedeclareerd. Ze worden gebruikt om code te analyseren tijdens compilatie of tijdens runtime. U kunt een annotatie zien als een label, tag of compilerhint.

Annotaties ben je waarschijnlijk al eens tegengekomen. Als we bijvoorbeeld een methode van de bovenliggende klasse overschrijven, schrijven we @Override voor de methode zelf. Deze annotatie geeft aan dat de methode van de ouder wordt overschreven in de onderliggende klasse.

Syntaxis:


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

Ik wil meteen opmerken dat annotaties niet alleen van toepassing zijn op methoden. Ze worden gebruikt met pakketten, klassen, methoden, velden en parameters.

Om te begrijpen hoe annotaties werken, maken we eerst kennis met het concept van een markeringsinterface. Sinds de komst van Java hebben ontwikkelaars altijd een manier nodig gehad om klassen te markeren om er bepaalde acties op uit te voeren.

Vóór Java 5 gebruikten ze een interface die niet deed wat we van interfaces verwachten. Het had geen methoden en geen contract. Het markeerde op de een of andere manier gewoon een klas als speciaal.

Zo'n interface werd een markerinterface genoemd. Uit de naam zou je kunnen raden dat het doel is om klassen te markeren voor de JVM, compiler of een bibliotheek. Sommige markeringsinterfaces, zoals Serializable , blijven bestaan. Met deze markerinterface kunnen we aangeven dat instanties van een klasse kunnen worden geserialiseerd.

Zoals we hebben gezien, blijven markeringsinterfaces voortleven, zelfs na de introductie van annotaties.

Annotaties versus markeringsinterfaces:


@MyAnnotation
public class MyClass {}

public class MyClass implements MarkerInterface {}

Beide benaderingen hebben hetzelfde doel, maar er is een duidelijk verschil in de uitvoering ervan. Beschouw bijvoorbeeld een interface en een annotatie die aangeeft dat een klasse tot een bepaald type behoort.

Als we een interface gebruiken, markeren we de klasse. Als we het verkeerd gebruiken en er treedt een fout op, dan ontdekken we het probleem bij het compileren en zal het programma niet werken.

Met annotaties is alles niet zo eenvoudig: hier wordt de fout tijdens runtime gedetecteerd, wat betekent dat het programma start, maar het is niet verwonderlijk dat het niet wordt voltooid.

Merk op dat als we een klasse moeten markeren voor toekomstig gebruik, de instanties ervan moeten worden doorgegeven aan een specifieke methode:


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
}

Een markeringsinterface werkt hier het beste.

Het is het beste om annotaties te gebruiken wanneer we iets meer nodig hebben, zoals de parameters die annotaties ondersteunen.

Laten we eens kijken naar de standaardannotaties in de JDK:

Annotatie Beschrijving Voorbeeld
@Overschrijven Specificeert dat een methode de methode van een superklasse overschrijft of een methode van een abstracte klasse of interface implementeert.

@Override
public int hashCode() {
        return super.hashCode();
}
@Verouderd Markeert code als verouderd.

@Deprecated
public abstract void method();
@SuppressWarnings Schakelt compilerwaarschuwingen uit voor het geannoteerde element. Merk op dat als u meerdere waarschuwingscategorieën moet uitschakelen, deze tussen accolades moeten staan, bijvoorbeeld @SuppressWarnings({"unchecked", "cast"}) .

public class DocumentsFolder {
   private List documents;

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

In dit voorbeeld proberen we iets toe te voegen aan een lijst die geen gedefinieerd type heeft (een generiek type). De compiler zal ons hiervoor waarschuwen. Dit is erg handig, maar soms zijn er te veel "waarschuwingen" en kunnen ze luidruchtig zijn. U kunt deze annotatiemethode gebruiken en een type compilerwaarschuwing als argument opgeven. Er zijn veel markeringen, dus maak je geen zorgen om ze allemaal te onthouden — IDEA zal je meestal vertellen welke je moet toevoegen.

Nog een voorbeeld met meerdere argumenten:


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