Bagaimana anotasi seperti @Override berfungsi secara internal di Java?

93

Adakah yang bisa menjelaskan kepada saya bagaimana anotasi bekerja secara internal di java?

Saya tahu bagaimana kita bisa membuat anotasi kustom dengan menggunakan perpustakaan java.lang.annotation di java. Tapi saya masih belum mengerti cara kerjanya secara internal misalnya, anotasi @Override.

Saya akan sangat berterima kasih jika ada yang bisa menjelaskannya secara detail.

Chirag Dasani
sumber
4
Apa yang Anda maksud dengan "bekerja secara internal"? Kompiler? Runtime?
chrylis -cautiouslyoptimistic-
3
@chrylis Bekerja secara internal berarti bagaimana otomatis teridentifikasi bahwa metode ini adalah metode timpa atau yang ini bukan metode timpa. Ini bekerja pada kedua waktu tersebut. seperti pekerjaan anotasi timpa dalam waktu kompilasi dan anotasi pengontrol pegas berfungsi saat runtime
Chirag Dasani

Jawaban:

138

Perbedaan utama pertama antara jenis anotasi adalah apakah anotasi digunakan pada waktu kompilasi dan kemudian dibuang (suka @Override) atau ditempatkan di file kelas yang dikompilasi dan tersedia saat runtime (seperti Spring @Component). Ini ditentukan oleh kebijakan @Retensi anotasi. Jika Anda menulis anotasi Anda sendiri, Anda harus memutuskan apakah anotasi berguna pada waktu proses (untuk konfigurasi otomatis, mungkin) atau hanya pada waktu kompilasi (untuk pemeriksaan atau pembuatan kode).

Saat mengompilasi kode dengan anotasi, kompilator melihat anotasi seperti ia melihat pengubah lain pada elemen sumber, seperti pengubah akses ( public/ private) atau final. Saat menemukan anotasi, ia menjalankan pemroses anotasi, yang seperti kelas plug-in yang mengatakan tertarik pada anotasi tertentu. Pemroses anotasi umumnya menggunakan API Refleksi untuk memeriksa elemen yang sedang dikompilasi dan dapat dengan mudah menjalankan pemeriksaan pada mereka, memodifikasinya, atau menghasilkan kode baru untuk dikompilasi. @Overrideadalah contoh yang pertama; ia menggunakan API Refleksi untuk memastikannya dapat menemukan kecocokan untuk tanda tangan metode di salah satu kelas super dan menggunakan Messageruntuk menyebabkan kesalahan kompilasi jika tidak bisa.

Ada sejumlah tutorial yang tersedia tentang menulis pemroses anotasi; inilah yang berguna . Melihat melalui metode di dalam Processorantarmuka untuk bagaimana compiler memanggil prosesor penjelasan; operasi utama berlangsung dalam processmetode, yang dipanggil setiap kali kompilator melihat elemen yang memiliki anotasi yang cocok.

chrylis -cautiouslyoptimistic-
sumber
4
akan menyenangkan untuk menunjukkan kepada kami bagaimana tepatnya pemroses anotasi Spring mengurai @Component dan menyuntikkan kelas ke dalam wadahnya
Junchen Liu
@shanyangqu Itu di luar topik untuk pertanyaan, yang bukan khusus Musim Semi. Anda dapat membaca sendiri kelas postprocessor.
chrylis -cautiouslyoptimistic-
42

Selain apa yang disarankan orang lain, saya sarankan Anda menulis anotasi yang disesuaikan dan prosesornya dari awal untuk melihat cara kerja anotasi.

Di saya sendiri, misalnya, saya telah menulis anotasi untuk memeriksa apakah metode kelebihan beban dalam waktu kompilasi.

Pertama, buat anotasi bernama Overload. Anotasi ini diterapkan ke metode jadi saya menganotasinya dengan@Target(value=ElementType.METHOD)

package gearon.customAnnotation;

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

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

}

Selanjutnya, buat prosesor yang sesuai untuk menangani elemen yang dianotasi oleh anotasi yang ditentukan. Untuk metode yang diberi anotasi @Overload, tanda tangannya harus muncul lebih dari satu kali. Atau kesalahan dicetak.

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

Setelah memaketkan anotasi dan prosesnya menjadi file jar, buat kelas dengan @Overloaddan gunakan javac.exe untuk mengkompilasinya.

import gearon.customAnnotation.Overload;

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

    @Overload
    public static void foo(String s){

    }

    @Overload
    public static void nonOverloadedMethod(){

    }
} 

Karena nonOverloadedMethod()belum benar-benar kelebihan beban, kita akan mendapatkan keluaran seperti di bawah ini:

masukkan deskripsi gambar di sini

Eugene
sumber
Info di atas sangat menghormati JDK6 (+1 untuk itu), tetapi bagaimana cara mencapai hal yang sama menggunakan JDK5 juga? Menggunakan JDK6 SupportedAnnotationTypes, class AbstractProcessor menjadi lebih sederhana tetapi bagaimana hal yang sama terjadi di masa lalu (seperti Spring FrameWork 2.5 di jdk5)? Bagaimana JVM mendeteksi prosesor anotasi seperti class di jdk5? bisakah Anda memandu dengan mengedit jawaban dalam 2 bagian (satu untuk JDK5, Versi Saat Ini Untuk Jdk6 +)?
prajitgandhi
Di kelas Anda OverloadProcessor::processkenapa entry.getValue() == 1? Seseorang tidak perlu menambahkan anotasi di kelas / antarmuka induk, jadi roundEnv.getElementsAnnotatedWith(Overload.class)tidak akan mendapatkan kelas / antarmuka induk, bukan?
Hujan
Saya bingung di bagian ini tetapi saya pikir jawaban Anda sangat membantu.
Hujan
@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ Jika sebuah metode diperlakukan sebagai Overload, setidaknya harus ada metode lain dengan nama yang sama yang ditentukan di Kelas.
Eugene
1
@ Rain untuk metode yang mengatakan Overloaded, itu harus muncul lebih dari sekali di kelas yang sama, tetapi jika `== 1` maka itu adalah kesalahan.
KrishPrabakar
5

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

Tidak ada yang istimewa tentangnya yang membedakannya dari anotasi yang mungkin Anda tulis sendiri. Bit yang menarik ada di konsumen anotasi. Untuk anotasi seperti @Override, itu akan ada di compiler Java itu sendiri, atau alat analisis kode statis, atau IDE Anda.

Matt Ball
sumber
1
Saya tahu kode sumber penjelasan Override itu. Tapi bagaimana itu bekerja secara internal. seperti bagaimana dapat diidentifikasi metode ini bukan metode pengesampingan atau yang ini adalah metode pengesampingan? atau dapatkah saya membuat anotasi penggantian kustom saya? dan itu harus bekerja dengan perilaku yang persis sama seperti java override annotation
Chirag Dasani
3
Seperti yang saya katakan dalam jawaban saya, perilaku bukanlah bagian dari anotasi. Penafsirannya terletak pada hal-hal yang mengkonsumsi anotasi. Karena itu, kecuali Anda mengubah konsumen, Anda tidak dapat membuat versi ubahsuaian Anda sendiri @Override(atau anotasi standar lainnya).
Matt Ball
3

Pada dasarnya anotasi hanyalah penanda yang dibaca oleh kompilator atau aplikasi. Bergantung pada kebijakan retensinya, mereka tersedia pada waktu kompilasi saja atau dapat dibaca pada waktu proses menggunakan refleksi.

Banyak kerangka kerja menggunakan retensi waktu proses, yaitu mereka secara reflektif memeriksa apakah beberapa anotasi ada di kelas, metode, bidang, dll. Dan melakukan sesuatu jika anotasi ada (atau tidak). Selain itu, anggota anotasi dapat digunakan untuk menyampaikan informasi lebih lanjut.

Thomas
sumber
3

Ikuti tautan ini . Ini akan memberikan jawaban dekat untuk masalah Anda. Jika kita berfokus pada anotasi di Java, Anotasi diperkenalkan di Java 5 dan bukan khusus Spring. Secara umum, anotasi memungkinkan Anda menambahkan metadata ke kelas, metode, atau variabel. Anotasi dapat diinterpretasikan oleh kompilator (misalnya, anotasi @Override) atau oleh kerangka kerja seperti pegas (misalnya, anotasi @Component).

Selain itu saya menambahkan lebih banyak referensi.

  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
sumber
@LuiggiMendoza java 1.7 anotasi doc ditambahkan
Ruchira Gayan Ranaweera
@Ruchira saya membuka semua tautan tetapi masih saya belum jelas cara kerjanya. Bisakah Anda menjelaskan saya secara detail seperti pertimbangkan sebagai anotasi musim semi. Saya dapat melakukan semua hal dengan menggunakan anotasi tanpa menulis konfigurasi apa pun di file spring.xml. apakah itu secara internal mengikat anotasi ke konfigurasi xml?
Chirag Dasani
@ChiragDasani lihat ini. ini dapat membantu Anda static.springsource.org/spring/docs/3.0.0.M3/reference/html/… dan juga lihat posting SO ini stackoverflow.com/questions/2798181/…
Ruchira Gayan Ranaweera
0

Bahkan saya mencari jawaban dari pertanyaan yang sama. tautan di bawah ini menyediakan hal-hal bagus yang terkonsolidasi untuk mendapatkan bagian dalam anotasi. https://dzone.com/articles/how-annotations-work-java Semoga membantu!

Kusum
sumber