2012-04-10 64 views
58

我有一個父類Parent和子類Child,這樣定義:Java方法註釋如何與方法重寫一起使用?

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

如果我獲得Method參考Child::foo,將childFoo.getAnnotation(MyAnnotation.class)給我@MyAnnotation?或者它會是null

我更感興趣的是更多地瞭解註解是如何處理Java繼承的。

回答

60

http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations.html#annotation-inheritance逐字複製:

註釋繼承

重要的是要了解有關注釋的繼承規則,因爲這些都基於存在的連接點匹配的軸承或缺少註釋。

默認情況下,註釋不會被繼承。考慮下面的程序

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

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

然後Sub沒有MyAnnotation註釋,並且,Sub.foo()不是@Oneway方法,儘管它覆蓋Super.foo()這是事實。

如果註釋類型具有元註釋@Inherited,那麼該類上的註釋將導致註釋被子類繼承。因此,在上例中,如果MyAnnotation類型具有@Inherited屬性,則Sub將具有MyAnnotation註釋。

@Inherited當用於註釋除類型以外的任何其他註釋時,不會繼承註釋。實現一個或多個接口的類型永遠不會從它實現的接口繼承任何註釋。

+34

此外,trutheality,* I *搜索之前,我問,我想出了這個頁面。恭喜,您現在已成爲搜索結果的一部分。這就是爲什麼這個網站在這裏。 :)另外,您的答案比翻閱該文檔要簡潔得多。 – Tustin2121 2013-03-26 15:10:58

+1

有一個問題需要進一步...如果一個框架找到基於註解的方法,然後調用它,哪個版本的方法被調用?子類的方法應該重寫父類,但是是否需要使用反射調用? – 2014-08-21 13:53:55

9

您已經找到答案了:JDK中沒有提供方法標註繼承的規定。

但攀登搜索的註釋方法的超類鏈也很容易實現:

/** 
* 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

這並沒有規定在任何超類實現中找不到所請求的註釋的情況 - 在這種情況下,它將拋出「NoSuchMethodException」,儘管「null」將是合法的返回值... – 2015-06-16 10:36:35

+0

@UriAgassi那是設計。我認爲JavaDoc說得很清楚。 – Saintali 2015-06-19 20:51:22

+0

javadoc唯一清楚的是拋出了'NoSuchMethodException'。它在_方法不存在_時不應該拋出這樣一個異常,而不是在找不到註釋時_...它與原始實現不兼容(在這種情況下它將返回'null') – 2015-06-20 06:28:20

2

雖然作爲問問題的答案是Java的Method.getAnnotation()不考慮替代的方法,有時是有用的找到這些註釋。下面是我目前使用的Saintali的回答更完整的版本:

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