คำอธิบายประกอบเช่น @Override ทำงานภายใน Java ได้อย่างไร


93

ใครช่วยอธิบายให้ฉันฟังว่าคำอธิบายประกอบทำงานภายใน java ได้อย่างไร

ฉันรู้ว่าเราสามารถสร้างคำอธิบายประกอบแบบกำหนดเองได้อย่างไรโดยใช้ไลบรารี java.lang.annotation ใน java แต่ฉันยังไม่เข้าใจว่ามันทำงานอย่างไรภายในเช่นคำอธิบายประกอบ @Override

ฉันจะขอบคุณมากถ้าใครสามารถอธิบายโดยละเอียดได้


4
คำว่า "ทำงานภายใน" หมายความว่าอย่างไร คอมไพเลอร์? รันไทม์?
chrylis -cautiouslyoptimistic-

3
@chrylis Work เป็นการภายในหมายถึงวิธีที่ระบุโดยอัตโนมัติว่าวิธีนี้เป็นวิธีการแทนที่หรือวิธีนี้ไม่ใช่วิธีการแทนที่ มันทำงานได้ทั้งสองเวลา เช่นการแทนที่คำอธิบายประกอบในเวลาคอมไพล์และคำอธิบายประกอบตัวควบคุมสปริงทำงานในรันไทม์
Chirag Dasani

คำตอบ:


138

ความแตกต่างหลักประการแรกระหว่างประเภทของคำอธิบายประกอบคือไม่ว่าจะใช้ในเวลาคอมไพล์แล้วทิ้ง (ชอบ@Override) หรือวางไว้ในไฟล์คลาสที่คอมไพล์แล้วและพร้อมใช้งานที่รันไทม์ (เช่น Spring's @Component) ซึ่งกำหนดโดยนโยบาย@Retentionของคำอธิบายประกอบ หากคุณกำลังเขียนคำอธิบายประกอบของคุณเองคุณจะต้องตัดสินใจว่าคำอธิบายประกอบนั้นมีประโยชน์ในรันไทม์ (สำหรับการกำหนดค่าอัตโนมัติอาจ) หรือเฉพาะในเวลาคอมไพล์ (สำหรับการตรวจสอบหรือการสร้างโค้ด)

เมื่อรวบรวมรหัสที่มีคำอธิบายประกอบคอมไพเลอร์เห็นคำอธิบายประกอบเช่นเดียวกับมันเห็นการปรับเปลี่ยนองค์ประกอบอื่น ๆ เกี่ยวกับแหล่งที่มาเช่นการปรับเปลี่ยนการเข้าถึง ( public/ private) finalหรือ เมื่อพบคำอธิบายประกอบจะเรียกใช้ตัวประมวลผลคำอธิบายประกอบซึ่งเหมือนกับคลาสปลั๊กอินที่ระบุว่าสนใจคำอธิบายประกอบเฉพาะ โดยทั่วไปตัวประมวลผลคำอธิบายประกอบจะใช้ Reflection API เพื่อตรวจสอบองค์ประกอบที่กำลังคอมไพล์และอาจเรียกใช้การตรวจสอบแก้ไขแก้ไขหรือสร้างโค้ดใหม่เพื่อรวบรวม @Overrideเป็นตัวอย่างแรก; ใช้ Reflection API เพื่อให้แน่ใจว่าสามารถค้นหาลายเซ็นเมธอดที่ตรงกันใน superclasses ใดคลาสหนึ่งและใช้Messagerเพื่อทำให้เกิดข้อผิดพลาดในการคอมไพล์หากไม่สามารถทำได้

มีบทเรียนมากมายเกี่ยวกับการเขียนตัวประมวลผลคำอธิบายประกอบ นี่เป็นประโยชน์อย่างใดอย่างหนึ่ง มองผ่านวิธีการในอินเตอร์เฟซสำหรับวิธีคอมไพเลอร์จะเรียกหน่วยประมวลผลคำอธิบายประกอบ; การดำเนินการหลักเกิดขึ้นในเมธอดซึ่งถูกเรียกทุกครั้งที่คอมไพเลอร์เห็นองค์ประกอบที่มีคำอธิบายประกอบที่ตรงกันProcessorprocess


4
จะเป็นการดีที่จะชี้ให้เราทราบว่าหน่วยประมวลผลคำอธิบายประกอบของ Spring แยกวิเคราะห์ @Component และฉีดคลาสลงในคอนเทนเนอร์อย่างไร
Junchen Liu

@shanyangqu นั่นไม่ใช่ประเด็นสำหรับคำถามซึ่งไม่ใช่เฉพาะฤดูใบไม้ผลิ คุณสามารถอ่านชั้นเรียนของตัวประมวลผลภายหลังด้วยตัวคุณเอง
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 ได้อย่างไร คุณช่วยแนะนำโดยแก้ไขคำตอบใน 2 ส่วน (อันหนึ่งสำหรับ JDK5 เวอร์ชันปัจจุบันสำหรับ Jdk6 +) ได้ไหม
prajitgandhi

ในชั้นเรียนของคุณOverloadProcessor::processทำไมถึงเป็นเช่นนั้นentry.getValue() == 1? ไม่จำเป็นต้องเพิ่มคำอธิบายประกอบที่คลาส / อินเทอร์เฟซหลักดังนั้นroundEnv.getElementsAnnotatedWith(Overload.class)จะไม่ได้รับคลาส / อินเทอร์เฟซหลักใช่ไหม
ฝนตก

ฉันสับสนในส่วนนี้ แต่ฉันคิดว่าคำตอบของคุณมีประโยชน์มาก
ฝนตก

@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ถ้าเมธอดถูกถือว่าเป็น Overload ควรมีเมธอดอื่นที่มีชื่อเดียวกันกำหนดไว้ในคลาสเป็นอย่างน้อย
ยูจีน

1
@Raining สำหรับวิธีการที่จะบอกว่า Overloaded จะต้องปรากฏมากกว่าหนึ่งครั้งในคลาสเดียวกัน แต่ถ้าเป็น "== 1" แสดงว่าเป็นข้อผิดพลาด
KrishPrabakar

5

ต่อไปนี้คือ@Override: http://www.docjar.com/html/api/java/lang/Override.java.html

ไม่มีอะไรพิเศษเกี่ยวกับเรื่องนี้ที่ทำให้แตกต่างจากคำอธิบายประกอบที่คุณอาจเขียนเอง บิตที่น่าสนใจอยู่ในผู้บริโภคของคำอธิบายประกอบ สำหรับคำอธิบายประกอบเช่น@Overrideนั้นจะอยู่ในคอมไพเลอร์ Java เองหรือเครื่องมือวิเคราะห์โค้ดแบบคงที่หรือ IDE ของคุณ


1
ฉันรู้ซอร์สโค้ดของคำอธิบายประกอบการแทนที่ แต่วิธีการทำงานภายใน เช่นวิธีการระบุวิธีการนี้ไม่ใช่วิธีการแทนที่หรือวิธีนี้เป็นวิธีการแทนที่? หรือฉันสามารถสร้างคำอธิบายประกอบการลบล้างที่กำหนดเองได้หรือไม่ และมันควรจะทำงานเหมือนกันทุกประการเช่นคำอธิบายประกอบการแทนที่ java
Chirag Dasani

3
ดังที่ฉันได้กล่าวไว้ในคำตอบของฉันพฤติกรรมไม่ได้เป็นส่วนหนึ่งของคำอธิบายประกอบ การตีความอยู่ในสิ่งที่ใช้คำอธิบายประกอบ ด้วยเหตุนี้หากคุณไม่เปลี่ยนผู้บริโภคคุณจะไม่สามารถสร้างเวอร์ชันที่กำหนดเองของคุณเอง@Override(หรือคำอธิบายประกอบมาตรฐานอื่น ๆ ) ได้
Matt Ball

3

โดยทั่วไปคำอธิบายประกอบเป็นเพียงเครื่องหมายซึ่งอ่านโดยคอมไพเลอร์หรือแอปพลิเคชัน ขึ้นอยู่กับนโยบายการเก็บรักษาของพวกเขาพวกเขาพร้อมใช้งานในเวลาคอมไพล์เท่านั้นหรือสามารถอ่านได้ที่รันไทม์โดยใช้การสะท้อน

เฟรมเวิร์กจำนวนมากใช้การเก็บรักษารันไทม์กล่าวคือตรวจสอบอย่างไตร่ตรองว่าคำอธิบายประกอบบางส่วนมีอยู่ในคลาสวิธีการฟิลด์และอื่น ๆ หรือไม่และทำอะไรบางอย่างหากมีคำอธิบายประกอบอยู่ (หรือไม่) นอกจากนี้สมาชิกของคำอธิบายประกอบสามารถใช้เพื่อส่งต่อข้อมูลเพิ่มเติมได้


3

ตามลิงค์นี้เลย สิ่งนี้จะให้คำตอบที่ใกล้เคียงสำหรับปัญหาของคุณ หากเรามุ่งเน้นไปที่คำอธิบายประกอบคำอธิบายJavaประกอบจะถูกนำมาใช้ใน Java 5 และไม่ใช่เฉพาะฤดูใบไม้ผลิ โดยทั่วไปคำอธิบายประกอบช่วยให้คุณสามารถเพิ่มข้อมูลเมตาลงในคลาสวิธีการหรือตัวแปรได้ คอมไพเลอร์สามารถตีความคำอธิบายประกอบ (ตัวอย่างเช่นคำอธิบายประกอบ @Override) หรือตามกรอบงานเช่น spring (ตัวอย่างเช่นคำอธิบายประกอบ @Component)

นอกจากนี้ฉันกำลังเพิ่มการอ้างอิงเพิ่มเติม

  1. http://www.codeproject.com/Articles/272736/Understand-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 annotation doc added
Ruchira Gayan Ranaweera

@Ruchira ฉันเปิดลิงค์ทั้งหมด แต่ฉันยังไม่เคลียร์ว่ามันทำงานอย่างไร คุณสามารถอธิบายรายละเอียดได้ไหมเช่นพิจารณาเป็นคำอธิบายประกอบฤดูใบไม้ผลิ ฉันสามารถทำทุกอย่างได้โดยใช้คำอธิบายประกอบโดยไม่ต้องเขียนการกำหนดค่าใด ๆ ในไฟล์ spring.xml มันผูกคำอธิบายประกอบภายในกับคอนฟิกูเรชัน xml หรือไม่
Chirag Dasani

@ChiragDasani ลองดูนี่สิ สิ่งนี้อาจช่วยคุณได้static.springsource.org/spring/docs/3.0.0.M3/reference/html/…และดู SO post stackoverflow.com/questions/2798181/…
Ruchira Gayan Ranaweera

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.