2012-04-10 35 views
58

Tôi đã một lớp cha mẹ Parent và một lớp con Child, được xác định như sau:Chú thích phương thức Java hoạt động kết hợp với phương pháp ghi đè như thế nào?

class Parent { 
    @MyAnnotation("hello") 
    void foo() { 
     // implementation irrelevant 
    } 
} 
class Child { 
    @Override 
    foo() { 
     // implementation irrelevant 
    } 
} 

Nếu tôi có được một tài liệu tham khảo Method-Child::foo, sẽ childFoo.getAnnotation(MyAnnotation.class) cho tôi @MyAnnotation? Hay nó sẽ là null?

Tôi quan tâm hơn về cách thức hoặc liệu chú thích có hoạt động với kế thừa Java hay không.

Trả lời

60

sao chép nguyên văn từ http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations.html#annotation-inheritance:

Chú Inheritance

Điều quan trọng để hiểu các quy tắc liên quan đến thừa kế của chú thích là, như những có một mang về tham gia phù hợp với quan điểm dựa trên sự hiện diện hay không có chú thích.

Theo chú thích mặc định không được kế thừa. Căn cứ vào chương trình sau

 @MyAnnotation 
     class Super { 
      @Oneway public void foo() {} 
     } 

     class Sub extends Super { 
      public void foo() {} 
     } 

Sau đó Sub không có MyAnnotation chú thích, và Sub.foo() không phải là một phương pháp @Oneway, mặc dù thực tế là nó sẽ ghi đè Super.foo() đó là.

Nếu loại chú thích có chú giải meta @Inherited thì chú thích loại đó trên một lớp sẽ khiến lớp phụ kế thừa chú thích. Vì vậy, trong ví dụ trên, nếu loại MyAnnotation có thuộc tính @Inherited, thì Sub sẽ có chú thích MyAnnotation.

@Inherited chú thích không được kế thừa khi được sử dụng để chú thích bất kỳ điều gì khác ngoài loại. Một loại thực hiện một hoặc nhiều giao diện không bao giờ kế thừa bất kỳ chú thích nào từ các giao diện mà nó thực hiện.

+34

Ngoài ra, trutheality, * Tôi * đã tìm kiếm trước khi tôi hỏi, và tôi đã đưa ra trang này. Xin chúc mừng, bạn hiện là một phần của những kết quả tìm kiếm đó. Đó là lý do tại sao trang web này là ở đây. :) Ngoài ra, câu trả lời của bạn ngắn gọn hơn nhiều so với việc xem xét tài liệu đó. – Tustin2121

+1

Một câu hỏi để tiếp tục điều này ... nếu một khung tìm phương thức dựa trên chú thích và sau đó gọi nó, phiên bản nào của phương thức được gọi? Phương thức của lớp con nên ghi đè phụ huynh nhưng nó được tôn trọng với lời gọi phản xạ? –

9

Bạn đã tìm thấy câu trả lời của mình: không có quy định về kế thừa chú thích phương pháp trong JDK.

Nhưng leo chuỗi siêu hạng nhất trong việc tìm kiếm các phương pháp chú giải cũng rất dễ dàng để thực hiện:

/** 
* Climbs the super-class chain to find the first method with the given signature which is 
* annotated with the given annotation. 
* 
* @return A method of the requested signature, applicable to all instances of the given 
*   class, and annotated with the required annotation 
* @throws NoSuchMethodException If no method was found that matches this description 
*/ 
public Method getAnnotatedMethod(Class<? extends Annotation> annotation, 
           Class c, String methodName, Class... parameterTypes) 
     throws NoSuchMethodException { 

    Method method = c.getMethod(methodName, parameterTypes); 
    if (method.isAnnotationPresent(annotation)) { 
     return method; 
    } 

    return getAnnotatedMethod(annotation, c.getSuperclass(), methodName, parameterTypes); 
} 
+0

Điều này không quy định trong trường hợp không tìm thấy chú thích được yêu cầu trong bất kỳ triển khai siêu lớp nào - trong trường hợp này nó sẽ ném 'NoSuchMethodException', mặc dù' null' sẽ là giá trị trả về hợp lệ ... –

+0

@UriAgassi thiết kế. Tôi nghĩ rằng JavaDoc làm cho nó rõ ràng. – Saintali

+0

điều duy nhất javadoc làm cho rõ ràng là một 'NoSuchMethodException' được ném. Nó _should_ ném một ngoại lệ như vậy khi phương thức _ không tồn tại_, không phải khi không tìm thấy chú thích _... nó không tương thích với thực thi ban đầu (sẽ trả về 'null' trong trường hợp này) –

2

Trong khi câu trả lời cho những câu hỏi như hỏi là Java Method.getAnnotation() không xem xét phương pháp ghi đè, đôi khi nó là hữu ích để tìm các chú thích này. Dưới đây là một phiên bản hoàn chỉnh hơn về câu trả lời Saintali rằng Tôi hiện đang sử dụng:

public static <A extends Annotation> A getInheritedAnnotation(
    Class<A> annotationClass, AnnotatedElement element) 
{ 
    A annotation = element.getAnnotation(annotationClass); 
    if (annotation == null && element instanceof Method) 
     annotation = getOverriddenAnnotation(annotationClass, (Method) element); 
    return annotation; 
} 

private static <A extends Annotation> A getOverriddenAnnotation(
    Class<A> annotationClass, Method method) 
{ 
    final Class<?> methodClass = method.getDeclaringClass(); 
    final String name = method.getName(); 
    final Class<?>[] params = method.getParameterTypes(); 

    // prioritize all superclasses over all interfaces 
    final Class<?> superclass = methodClass.getSuperclass(); 
    if (superclass != null) 
    { 
     final A annotation = 
      getOverriddenAnnotationFrom(annotationClass, superclass, name, params); 
     if (annotation != null) 
      return annotation; 
    } 

    // depth-first search over interface hierarchy 
    for (final Class<?> intf : methodClass.getInterfaces()) 
    { 
     final A annotation = 
      getOverriddenAnnotationFrom(annotationClass, intf, name, params); 
     if (annotation != null) 
      return annotation; 
    } 

    return null; 
} 

private static <A extends Annotation> A getOverriddenAnnotationFrom(
    Class<A> annotationClass, Class<?> searchClass, String name, Class<?>[] params) 
{ 
    try 
    { 
     final Method method = searchClass.getMethod(name, params); 
     final A annotation = method.getAnnotation(annotationClass); 
     if (annotation != null) 
      return annotation; 
     return getOverriddenAnnotation(annotationClass, method); 
    } 
    catch (final NoSuchMethodException e) 
    { 
     return null; 
    } 
} 
Các vấn đề liên quan