W 2005 roku, wraz z pojawieniem się języka Java 5, dowiedzieliśmy się o nowych obiektach zwanych adnotacjami.

Adnotacje to specjalna forma metadanych składniowych, które można zadeklarować w kodzie. Służą do analizy kodu podczas kompilacji lub podczas wykonywania programu. Adnotację można porównać do etykiety, znacznika lub wskazówki kompilatora.

Prawdopodobnie spotkałeś się już z adnotacjami. Na przykład, gdy nadpisujemy metodę klasy nadrzędnej, piszemy @Override przed samą metodą . Jest to adnotacja wskazująca, że ​​metoda nadrzędna zostanie zastąpiona w klasie pochodnej.

Składnia:

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

Od razu chcę zauważyć, że adnotacje mają zastosowanie nie tylko do metod, ponieważ są używane w połączeniu z pakietami, klasami, metodami, polami i parametrami.

Aby zrozumieć, jak działają adnotacje, zapoznajmy się najpierw z koncepcją interfejsu znaczników. Konieczność oznaczenia klasy w określony sposób w celu wykonania na niej określonych działań istniała dla programistów Java od czasu pojawienia się tego języka.

Przed Javą 5 używali interfejsu, który nawet nie przypominał samego siebie i nie odpowiadał zamierzonemu przeznaczeniu. Było bez metod, nie zawierało żadnej umowy, tylko oznaczało klasę do izolacji.

Taki interfejs nazwano interfejsem znacznikowym. Z nazwy wynika, że ​​jego zadaniem jest oznaczanie klas dla JVM, kompilatora, czy jakiejś biblioteki. Pozostało jeszcze kilka interfejsów znaczników, takich jak Serializable . Ten znacznik pozwala nam oznaczyć klasę komunikatem, że jej instancje mogą być serializowane.

Widzieliśmy, że korzystanie z interfejsów znaczników nadal istnieje, nawet po wprowadzeniu adnotacji.

Równoważne użycie interfejsu adnotacji i znaczników:

@MyAnnotation
public class MyClass {}
public class MyClass implements MarkerInterface {}

Pomimo tego, że zadanie obu podejść jest takie samo, istnieje wyraźna różnica w ich realizacji. Rozważmy na przykład interfejs i adnotację, aby określić, czy klasa należy do określonego typu.

W przypadku interfejsu zaznaczamy klasę: nawet jeśli zostanie użyty nieprawidłowo i wystąpi błąd, zostanie on wykryty na etapie kompilacji i program nie zostanie uruchomiony.

W przypadku adnotacji wszystko nie jest takie proste: błąd zostanie wykryty już w czasie wykonywania, co oznacza, że ​​\u200b\u200bprogram rozpocznie wykonywanie, ale zgodnie z oczekiwaniami nie zakończy się.

Należy zauważyć, że jeśli chcemy oznaczyć klasę do przyszłego użytku, jej instancje muszą zostać przekazane do określonej metody:

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
}

Interfejs znaczników działa tutaj najlepiej.

Adnotacje są najlepiej używane, gdy istnieje potrzeba czegoś więcej, na przykład parametrów, które adnotacja umożliwia przekazanie.

Spójrzmy na standardowe adnotacje w JDK:

adnotacja Opis Przykład
@Nadpisanie Określa, że ​​metoda zastępuje metodę klasy nadrzędnej lub implementuje metodę klasy abstrakcyjnej lub interfejsu.
@Override
public int hashCode() {
        return super.hashCode();
}
@Przestarzałe Oznacza kod jako przestarzały.
@Deprecated
public abstract void method();
@Tłumić ostrzeżenia Wyłącza ostrzeżenia kompilatora dla elementu z adnotacjami. Pamiętaj, że jeśli chcesz wyłączyć wiele kategorii ostrzeżeń, muszą one być ujęte w nawiasy klamrowe, na przykład @SuppressWarnings ({"unchecked", "cast"}) .
public class DocumentsFolder {
   private List documents;

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

W tym przykładzie próbujemy dodać do listy w metodzie, która nie ma zdefiniowanego typu (ogólnego). Kompilator ostrzeże nas o tym. Chociaż jest to bardzo przydatne, czasami jest zbyt wiele „ostrzeżeń” i są one bardzo głośne. W takim przypadku można użyć tej adnotacji metody z parametrem znacznika ostrzeżenia kompilatora. Znaczników jest bardzo dużo, więc nie trzeba wszystkiego pamiętać, zwykle IDEA podpowie, który położyć.

Inny przykład użycia z przekazywanymi wieloma parametrami:

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