เหตุใดคลาส java จึงไม่สืบทอดคำอธิบายประกอบจากอินเทอร์เฟซที่ใช้งาน


108

ฉันใช้ AOP ของ Guice เพื่อดักฟังการเรียกใช้วิธีการบางอย่าง ชั้นเรียนของฉันใช้อินเทอร์เฟซและฉันต้องการใส่คำอธิบายประกอบวิธีการเชื่อมต่อเพื่อให้ Guice สามารถเลือกวิธีการที่เหมาะสม แม้ว่าประเภทคำอธิบายประกอบจะถูกใส่คำอธิบายประกอบด้วยคลาสการใช้คำอธิบายประกอบที่สืบทอดมาจะไม่สืบทอดคำอธิบายประกอบตามที่ระบุไว้ในเอกสาร java ของการสืบทอด:

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

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

คำตอบ:


130

ฉันจะบอกว่าเหตุผลก็คือไม่เช่นนั้นปัญหาการสืบทอดหลายอย่างจะเกิดขึ้น

ตัวอย่าง:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Inherited
public @interface Baz { String value(); }

public interface Foo{
    @Baz("baz") void doStuff();
}

public interface Bar{
    @Baz("phleem") void doStuff();
}

public class Flipp{
    @Baz("flopp") public void doStuff(){}
}

public class MyClass extends Flipp implements Foo, Bar{}

ถ้าฉันทำสิ่งนี้:

MyClass.class.getMethod("doStuff").getAnnotation(Baz.class).value()

ผลลัพธ์จะเป็นอย่างไร 'baz', 'phleem' หรือ 'flopp'?


ด้วยเหตุนี้คำอธิบายประกอบบนอินเทอร์เฟซจึงไม่ค่อยมีประโยชน์


9
คำอธิบายประกอบบนอินเทอร์เฟซจะมีประโยชน์ก็ต่อเมื่อคุณมีกรอบงานที่รองรับ BTW ในตัวอย่างนี้ getAnnotation () คืนค่า null;)
Peter Lawrey

6
ฉันไม่รู้จักคน ในกรณีนี้ (หากไม่มีการพิมพ์ผิด) ฉันคาดว่าจะมีThe field value is ambiguous.ข้อผิดพลาดเหมือนคอมไพเลอร์เหมือนกับอินเทอร์เฟซสองรายการที่ประกาศค่าคงที่เท่ากันโดยมีค่าต่างกัน ฉันรู้ว่านี่ไม่ใช่ฟิลด์ แต่ค่าคำอธิบายประกอบจะได้รับการแก้ไขทั้งหมดในเวลาคอมไพล์ใช่ไหม คุณลักษณะที่เราขาดหายไปที่นี่จะเป็นประโยชน์อย่างยิ่งในหลาย ๆ กรณี ขออภัยที่รื้อโพสต์เก่าด้วย :)
Petr Janeček

7
@Slanec ดูวิธีที่แหล่งที่มาของ Spring เพื่อดูว่าพวก Spring แก้ปัญหาเหล่านี้อย่างไร ดูAnnotationUtils.findAnnotation (method, annotationType)
Sean Patrick Floyd

1
ฉันกำลังพิจารณาเขียนสิ่งที่คล้ายกับสิ่งนี้ ด้วยการแคชแบบง่ายๆนี้ดูเหมือนจะเป็นวิธีที่ดีสำหรับฉัน ขอบคุณ! ในตัวอย่างด้านบนจะพบFooคำอธิบายประกอบของ ( MyClassไม่มีหนึ่งรายการจากนั้นอินเทอร์เฟซจะถูกค้นหาและเรียงตามลำดับที่ตามหลังimplements) จึงพิมพ์ "baz" เย็น.
Petr Janeček

2
@WChargin จริงมันใช้เวลาเพียง 2 ปีสำหรับคนที่ระบุว่าพิมพ์ผิด :-)
Sean Patrick Floyd

35

จากJavadocสำหรับ @Inherited:

ระบุว่าประเภทคำอธิบายประกอบถูกสืบทอดโดยอัตโนมัติ หากคำอธิบายประกอบแบบเมตาที่สืบทอดมีอยู่ในการประกาศประเภทคำอธิบายประกอบและผู้ใช้สอบถามประเภทคำอธิบายประกอบบนการประกาศคลาสและการประกาศคลาสไม่มีคำอธิบายประกอบสำหรับประเภทนี้ซูเปอร์คลาสของคลาสจะถูกสอบถามโดยอัตโนมัติสำหรับประเภทคำอธิบายประกอบ กระบวนการนี้จะทำซ้ำจนกว่าจะพบคำอธิบายประกอบสำหรับประเภทนี้หรือถึงจุดสูงสุดของลำดับชั้นของคลาส (Object) หากไม่มี superclass มีคำอธิบายประกอบสำหรับประเภทนี้แบบสอบถามจะระบุว่าคลาสที่เป็นปัญหาไม่มีคำอธิบายประกอบดังกล่าว โปรดสังเกตว่าประเภทคำอธิบายประกอบแบบเมตานี้จะไม่มีผลหากใช้ชนิดคำอธิบายประกอบเพื่อใส่คำอธิบายประกอบอื่น ๆ นอกเหนือจากคลาส โปรดทราบด้วยว่าคำอธิบายประกอบเมตานี้ทำให้คำอธิบายประกอบที่สืบทอดมาจากคลาสระดับสูงเท่านั้น

ในทางกลับกันเครื่องมือตรวจสอบ JSR 305 จะทำการค้นหาการสืบทอดบางประเภท หากคุณมีลำดับชั้นของคลาส:

//Person.java
@Nonnull
 public Integer getAge() {...}

//Student.java (inherits from Person)
@Min(5)
public Integer getAge() {...}

จากนั้นการตรวจสอบที่มีประสิทธิภาพในการเป็นStudent.getAge() ไม่มีคำอธิบายประกอบเมตาดาต้า@Nonnull @Min(5)@Nonnull@Inherited


4
คำตอบนี้ควรเป็นคำตอบที่เลือก
Andrzej Purtak

3
ตัวอย่างของคุณขัดแย้งกับคำตอบของคุณซึ่งกล่าวว่า@Inheritedไม่มีผลกระทบต่อสิ่งอื่นใดนอกจากคลาส
Oleg Mikheev

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