Jak adnotacje, takie jak @Override, działają wewnętrznie w Javie?

93

Czy ktoś może mi wyjaśnić, jak adnotacje działają wewnętrznie w Javie?

Wiem, jak możemy tworzyć własne adnotacje za pomocą biblioteki java.lang.annotation w java. Ale nadal nie rozumiem, jak to działa wewnętrznie, na przykład adnotacja @Override.

Byłbym bardzo wdzięczny, gdyby ktoś mógł to szczegółowo wyjaśnić.

Chirag Dasani
źródło
4
Co rozumiesz przez „pracę wewnętrzną”? Kompilator? Środowisko wykonawcze?
chrylis
3
@chrylis Praca wewnętrznie oznacza, w jaki sposób jest ona automatycznie identyfikowana, że ​​ta metoda jest metodą zastępowania lub nie jest metodą zastępowania. Działa w obu przypadkach. jak nadpisywanie adnotacji działa w czasie kompilacji, a adnotacja kontrolera sprężynowego działa w czasie wykonywania
Chirag Dasani

Odpowiedzi:

138

Pierwszą główną różnicą między rodzajami adnotacji jest to, czy są one używane w czasie kompilacji, a następnie odrzucane (jak @Override), czy też umieszczane w skompilowanym pliku klasy i dostępne w czasie wykonywania (jak Spring @Component). Jest to określone przez zasadę @Retention adnotacji. Jeśli piszesz własną adnotację, musisz zdecydować, czy adnotacja jest pomocna w czasie wykonywania (na przykład do autokonfiguracji), czy tylko w czasie kompilacji (do sprawdzania lub generowania kodu).

Podczas kompilowania kodu z adnotacjami kompilator widzi adnotację tak samo, jak widzi inne modyfikatory w elementach źródłowych, takie jak modyfikatory dostępu ( public/ private) lub final. Kiedy napotka adnotację, uruchamia procesor adnotacji, który jest jak klasa wtyczki, która mówi, że interesuje go określona adnotacja. Procesor adnotacji na ogół używa interfejsu API Reflection do sprawdzania kompilowanych elementów i może po prostu przeprowadzać testy, modyfikować je lub generować nowy kod do skompilowania. @Overridejest przykładem pierwszego; używa interfejsu API Reflection, aby upewnić się, że może znaleźć dopasowanie do sygnatury metody w jednej z nadklas, a Messagerjeśli nie, używa do spowodowania błędu kompilacji.

Dostępnych jest wiele samouczków na temat pisania procesorów adnotacji; tutaj jest przydatny . Przejrzyj metod na tym Processorinterfejsie dla jak kompilator wywołuje procesor adnotacji; główna operacja odbywa się w processmetodzie, która jest wywoływana za każdym razem, gdy kompilator widzi element, który ma pasującą adnotację.

chrylis-ostrożnie optymistycznie-
źródło
4
byłoby miło wskazać nam dokładnie, w jaki sposób procesor adnotacji Springa analizuje @Component i wstrzykuje klasę do jego kontenera
Junchen Liu
@shanyangqu To pytanie nie na temat, które nie dotyczy wiosny. Możesz sam czytać klasy postprocesora.
chrylis
42

Oprócz tego, co sugerowali inni, radzę napisać od podstaw dostosowaną adnotację i jej procesor, aby zobaczyć, jak działa adnotacja.

Na przykład we własnym napisałem adnotację, aby sprawdzić, czy metody nie są przeciążone w czasie kompilacji.

Najpierw utwórz adnotację o nazwie Overload. Ta adnotacja jest stosowana do metody, więc dodaję do niej adnotację@Target(value=ElementType.METHOD)

package gearon.customAnnotation;

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

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

}

Następnie utwórz odpowiedni procesor do obsługi elementów opisanych za pomocą zdefiniowanej adnotacji. W przypadku metody z adnotacją przez @Overloadjej podpis musi pojawić się więcej niż jeden raz. Lub błąd zostanie wydrukowany.

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;
    }
}

Po spakowaniu adnotacji i jej przetworzeniu do pliku jar, utwórz klasę @Overloadi użyj javac.exe do jej skompilowania.

import gearon.customAnnotation.Overload;

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

    @Overload
    public static void foo(String s){

    }

    @Overload
    public static void nonOverloadedMethod(){

    }
} 

Ponieważ w nonOverloadedMethod()rzeczywistości nie został przeciążony, otrzymamy dane wyjściowe jak poniżej:

wprowadź opis obrazu tutaj

Eugene
źródło
Powyższe informacje to bardzo dobry szacunek dla JDK6 (+1 za to), ale jak osiągnąć to samo używając JDK5? Używając JDK6 SupportedAnnotationTypes, klasy AbstractProcessor stało się prostsze, ale jak to samo stało się w przeszłości (jak Spring FrameWork 2.5 na jdk5)? Jak JVM wykrywa procesor adnotacji, taki jak klasa w jdk5? czy możesz poprowadzić edycję odpowiedzi w sekcji 2 (jedna dla JDK5, aktualna wersja jest dla Jdk6 +)?
prajitgandhi
W twojej klasie, OverloadProcessor::processdlaczego tak jest entry.getValue() == 1? Nie trzeba dodawać adnotacji w klasie / interfejsie nadrzędnym, więc roundEnv.getElementsAnnotatedWith(Overload.class)nie otrzymamy klasy / interfejsu nadrzędnego, prawda?
Deszcz
Jestem zdezorientowany w tej części, ale myślę, że twoja odpowiedź jest bardzo pomocna.
Deszcz
@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ Jeśli metoda jest traktowana jako Overload, powinna istnieć przynajmniej inna metoda o tej samej nazwie zdefiniowana w klasie.
Eugene,
1
@Raining, aby metoda mówiła Overloaded, musi wystąpić więcej niż raz w tej samej klasie, ale jeśli jest to `== 1`, to jest to błąd.
KrishPrabakar
5

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

Nie ma w tym nic specjalnego, co odróżnia je od adnotacji, którą możesz napisać samodzielnie. Interesujące fragmenty są w konsumentach adnotacji. W przypadku adnotacji, takich jak @Override, byłoby to w samym kompilatorze języka Java, narzędziu do analizy kodu statycznego lub w środowisku IDE.

Matt Ball
źródło
1
Znam ten kod źródłowy adnotacji Zastąp. Ale jak to działa wewnętrznie. jak to można zidentyfikować ta metoda nie jest metodą zastępowania lub ta metoda jest metodą zastępowania? czy mogę utworzyć własną adnotację zastępującą? i powinno działać dokładnie tak samo, jak adnotacja zastępująca java
Chirag Dasani
3
Jak powiedziałem w mojej odpowiedzi, zachowanie nie jest częścią adnotacji. Interpretacja polega na tym, co konsumuje adnotację. Z tego powodu, o ile nie zmienisz konsumenta, nie możesz praktycznie stworzyć własnej niestandardowej wersji @Override(lub innych standardowych adnotacji).
Matt Ball
3

Zasadniczo adnotacje to tylko znaczniki odczytywane przez kompilator lub aplikację. W zależności od ich zasad przechowywania są one dostępne tylko w czasie kompilacji lub można je odczytać w czasie wykonywania przy użyciu odbicia.

Wiele frameworków używa retencji środowiska uruchomieniowego, tj. W sposób refleksyjny sprawdzają, czy w klasie, metodzie, polu itp. Istnieją adnotacje, i robią coś, jeśli adnotacja jest obecna (lub nie). Ponadto członkowie adnotacji mogą służyć do przekazywania dalszych informacji.

Tomasz
źródło
3

Kliknij ten link . Zapewni to dokładną odpowiedź na Twój problem. Jeśli skupiliśmy się na adnotacjach w programie Java, adnotacje zostały wprowadzone w Javie 5 i nie są specyficzne dla Springa. Ogólnie rzecz biorąc, adnotacje umożliwiają dodawanie metadanych do klasy, metody lub zmiennej. Adnotację można zinterpretować przez kompilator (na przykład adnotację @Override) lub strukturę, taką jak spring (na przykład adnotacja @Component).

Dodatkowo dodaję więcej referencji.

  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
źródło
@LuiggiMendoza java 1.7 adnotation doc added
Ruchira Gayan Ranaweera
@Ruchira otworzyłem wszystkie linki, ale nadal nie wiem, jak to działa. Czy możesz mi wyjaśnić szczegóły, takie jak uważaj za adnotacje wiosenne. Mogę zrobić wszystko, używając adnotacji bez zapisywania konfiguracji w pliku spring.xml. czy jest wewnętrznie powiązana adnotacja z konfiguracją XML?
Chirag Dasani
@ChiragDasani spójrz na to. to może ci pomóc static.springsource.org/spring/docs/3.0.0.M3/reference/html/ ... a także zobaczyć ten post SO stackoverflow.com/questions/2798181/ ...
Ruchira Gayan Ranaweera
0

Nawet ja szukałem odpowiedzi na to samo pytanie. poniższy link zapewnia skonsolidowane dobre informacje, aby uzyskać dostęp do wnętrza adnotacji. https://dzone.com/articles/how-annotations-work-java Mam nadzieję, że to pomoże!

Kusum
źródło