Как аннотации типа @Override работают внутри Java?


93

Может ли кто-нибудь объяснить мне, как аннотации работают внутри Java?

Я знаю, как мы можем создавать собственные аннотации с помощью библиотеки java.lang.annotation в java. Но я до сих пор не понимаю, как это работает внутри, например, аннотация @Override.

Я буду очень благодарен, если кто-нибудь сможет это объяснить подробно.


4
Что вы имеете в виду под «внутренней работой»? Компилятор? Время выполнения?
chrylis -cautiouslyoptimistic-

3
@chrylis Работа внутри означает, что автоматически определяется, что этот метод является методом переопределения или этот метод не является методом переопределения. Работают оба раза. например, переопределение аннотации работает во время компиляции, а аннотация весеннего контроллера работает во время выполнения
Чираг Дасани

Ответы:


138

Первое основное различие между видами аннотаций заключается в том, используются ли они во время компиляции, а затем отбрасываются (как @Override) или помещаются в скомпилированный файл класса и доступны во время выполнения (как Spring @Component). Это определяется политикой @Retention аннотации. Если вы пишете свою собственную аннотацию, вам нужно решить, будет ли она полезна во время выполнения (для автоконфигурации, возможно) или только во время компиляции (для проверки или генерации кода).

При компиляции кода с аннотациями компилятор видит аннотацию так же, как он видит другие модификаторы исходных элементов, такие как модификаторы доступа ( public/ private) или final. Когда он встречает аннотацию, он запускает обработчик аннотаций, который похож на класс подключаемого модуля, который говорит, что ему интересна конкретная аннотация. Обработчик аннотаций обычно использует Reflection API для проверки компилируемых элементов и может просто выполнять проверки, изменять их или генерировать новый код для компиляции. @Overrideэто пример первого; он использует Reflection API, чтобы убедиться, что он может найти совпадение для сигнатуры метода в одном из суперклассов, и использует, Messagerчтобы вызвать ошибку компиляции, если не может.

Существует ряд руководств по написанию процессоров аннотаций; вот полезный . Посмотрите с помощью методов на в Processorинтерфейсе для того, как компилятор вызывает процессор аннотаций; основная операция выполняется в processметоде, который вызывается каждый раз, когда компилятор видит элемент, имеющий соответствующую аннотацию.


4
было бы неплохо указать нам, как именно процессор аннотаций Spring анализирует @Component и внедряет класс в свой контейнер,
Джунчен Лю

@shanyangqu Это не по теме вопроса, который не относится к Spring. Вы можете сами прочитать классы постпроцессора.
chrylis -cautiouslyoptimistic-

42

Помимо того, что предлагали другие, я рекомендую вам написать индивидуальную аннотацию и ее обработчик с нуля, чтобы увидеть, как работает аннотация.

В моем собственном, например, я написал аннотацию, чтобы проверить, не перегружены ли методы во время компиляции.

Во-первых, создайте аннотацию с именем Overload. Эта аннотация применяется к методу, поэтому я аннотирую ее с помощью@Target(value=ElementType.METHOD)

package gearon.customAnnotation;

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

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

}

Затем создайте соответствующий процессор для обработки элементов, аннотированных заданной аннотацией. Для метода, аннотированного пользователем @Overload, его подпись должна появляться более одного раза. Или печатается ошибка.

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

После упаковки аннотации и ее обработки в файл jar создайте класс @Overloadи используйте 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(){

    }
} 

Поскольку nonOverloadedMethod()фактически не было перегрузки, мы получим результат, как показано ниже:

введите описание изображения здесь


Приведенная выше информация очень хорошо относится к JDK6 (+1 за это), но как добиться того же, используя JDK5? Используя JDK6 SupportedAnnotationTypes, класс AbstractProcessor, это стало проще, но как то же самое происходило в прошлом (например, Spring FrameWork 2.5 на jdk5)? Как JVM обнаруживает процессор аннотаций, такой как класс в jdk5? не могли бы вы направить, отредактировав ответ в двух разделах (один для JDK5, текущая версия для Jdk6 +)?
Prajitgandhi

OverloadProcessor::processПочему в вашем классе entry.getValue() == 1? Не нужно добавлять аннотацию к родительскому классу / интерфейсу, поэтому roundEnv.getElementsAnnotatedWith(Overload.class)не получится родительский класс / интерфейс, верно?
Raining

Я запутался в этой части, но я думаю, что ваш ответ очень полезен.
Raining

@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ Если метод обрабатывается как Overload, должен быть хотя бы другой метод с таким же именем, определенный в классе.
Евгений

1
@Raining для метода, чтобы сказать Overloaded, он должен появляться более одного раза в том же классе, но если это `== 1`, то это ошибка.
КришПрабакар

5

Вот @Override: http://www.docjar.com/html/api/java/lang/Override.java.html .

В нем нет ничего особенного, что отличает его от аннотации, которую вы можете написать самостоятельно. Интересные моменты находятся в потребителях аннотаций. В случае аннотации, например @Override, это может быть сам компилятор Java, инструмент статического анализа кода или ваша IDE.


1
Я знаю исходный код аннотации Override. Но как это работает внутри. например, как его можно идентифицировать, этот метод не является методом переопределения или это метод переопределения? или я могу создать собственную аннотацию переопределения? и он должен работать точно так же, как аннотация переопределения java
Чираг Дасани

3
Как я уже сказал в своем ответе, поведение не является частью аннотации. Интерпретация заключается в вещах, потребляющих аннотацию. Из-за этого, если вы не измените потребителя, вы практически не сможете создать свою собственную версию @Override(или другие стандартные аннотации).
Мэтт Болл,

3

По сути, аннотации - это просто маркеры, которые считываются компилятором или приложением. В зависимости от их политики хранения они доступны только во время компиляции или доступны для чтения во время выполнения с использованием отражения.

Многие фреймворки используют сохранение во время выполнения, т.е. они рефлексивно проверяют, присутствуют ли некоторые аннотации в классе, методе, поле и т. Д., И что-то делают, если аннотация присутствует (или нет). Кроме того, члены аннотаций могут использоваться для передачи дополнительной информации.


3

Перейдите по этой ссылке . Это даст подробный ответ на вашу проблему. Если мы сосредоточились на аннотациях Java, аннотации были введены в Java 5 и не относятся к Spring. Как правило, аннотации позволяют добавлять метаданные к классу, методу или переменной. Аннотация может интерпретироваться компилятором (например, аннотацией @Override) или фреймворком, таким как spring (например, аннотацией @Component).

Вдобавок добавляю еще ссылки.

  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

@LuiggiMendoza добавлен документ с аннотацией java 1.7
Ручира Гаян Ранауэра

@Ruchira, я открыл все ссылки, но до сих пор не понимаю, как это работает. Можете ли вы объяснить мне подробно, например, рассмотрим весенние аннотации. Я могу делать все, используя аннотации, без записи конфигурации в файл spring.xml. это внутренняя привязка аннотации к конфигурации xml?
Чираг Дасани

@ChiragDasani, взгляни на это. это может помочь вам static.springsource.org/spring/docs/3.0.0.M3/reference/html/…, а также см. это сообщение SO stackoverflow.com/questions/2798181/…
Ruchira Gayan Ranaweera

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.