Як анотації типу @Override працюють внутрішньо в Java?


93

Хто-небудь може пояснити мені, як анотації працюють внутрішньо в Java?

Я знаю, як ми можемо створювати власні анотації, використовуючи бібліотеку java.lang.annotation у Java. Але я все ще не розумію, як це працює внутрішньо, наприклад, анотація @Override.

Буду дуже вдячний, якщо хтось зможе пояснити це детально.


4
Що ви маєте на увазі під "внутрішньою роботою"? Компілятор? Час роботи?
chrisis

3
@chrylis Work interly означає, як автоматично визначається, що цей метод є методом заміщення або цей не є методом заміщення. Це робота обох часів. подібно перевизначенню роботи над анотацією під час компіляції, а анотація контролера пружини - це робота під час виконання
Chirag Dasani

Відповіді:


138

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

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

Існує ряд навчальних посібників з написання процесорів анотацій; ось корисний . Подивіться з допомогою методів на в Processorінтерфейсі для того, як компілятор викликає процесор анотацій; основна операція відбувається в processметоді, який викликається кожного разу, коли компілятор бачить елемент, що має відповідну анотацію.


4
було б непогано вказати нам, як саме процесор анотацій Spring аналізує @Component і вводить клас у його контейнер
Junchen Liu,

@shanyangqu Це поза темою для питання, яке не є специфічним для весни. Ви можете прочитати класи постпроцесора самостійно.
chrisis

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? чи можете ви допомогти, відредагувавши відповідь у 2 розділі (один для JDK5, поточна версія для Jdk6 +)?
праджітгандхі

OverloadProcessor::processЧому у вашому класі це entry.getValue() == 1? Не потрібно додавати анотацію до батьківського класу / інтерфейсу, тому батьківський клас / інтерфейс roundEnv.getElementsAnnotatedWith(Overload.class)не буде отримано, правда?
Дощ

Я збентежений у цій частині, але, думаю, ваша відповідь дуже корисна.
Дощ

@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ Якщо метод розглядається як Перевантаження, у Класі повинен бути принаймні інший метод з таким самим іменем.
Євген

1
@Raining для методу, щоб сказати Перевантажений, він повинен з'являтися більше одного разу в одному класі, але якщо це `== 1`, то це помилка.
KrishPrabakar

5

Ось @Override: http://www.docjar.com/html/api/java/lang/Override.java.html .

У ньому немає нічого особливого, що б відрізняло його від анотації, яку ви могли б написати самі. Цікаві шматочки є у споживачів анотацій. Для таких анотацій, як @Override, це буде у самому компіляторі Java, або засобі аналізу статичного коду, або вашому IDE.


1
Я знаю цей вихідний код анотації Override. Але як це працює внутрішньо. на зразок того, як це можна ідентифікувати, цей метод не є методом заміщення чи цей - методом заміщення? чи я можу створити власну анотацію заміщення? і це повинно працювати точно так само, як анотація заміни Java
Chirag Dasani

3
Як я вже сказав у своїй відповіді, поведінка не є частиною анотації. Інтерпретація полягає в тому, що споживає анотацію. Через це, якщо ви не зміните споживача, ви не зможете практично створити власну власну версію @Override(або інших стандартних анотацій).
Matt Ball

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 Gayan Ranaweera

@Ruchira мені відкрили всі посилання, але я все ще не зрозумів, як це працює. Чи можете ви пояснити мене в таких деталях, як розглядати як весняні анотації. Я можу зробити все, використовуючи анотацію, не записуючи жодної конфігурації у файл spring.xml. це внутрішня прив'язка анотації до конфігурації xml?
Chirag Dasani

@ChiragDasani погляньте на це. це може допомогти вам static.springsource.org/spring/docs/3.0.0.M3/reference/html / ... , а також побачити цей SO пост stackoverflow.com/questions/2798181 / ...
Ручіра Gayan Ranaweera

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.