Java方法注释如何与方法覆盖一起使用?


70

我有一个父类Parent和一个子类Child,因此定义为:

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

如果我得到Method参考Child::foochildFoo.getAnnotation(MyAnnotation.class)会给我@MyAnnotation吗?还是会null

我对注释如何与Java继承一起工作或是否与Java继承一起工作更感兴趣。

Answers:


82

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用于注释类型以外的其他注释时,注释不会继承。实现一个或多个接口的类型永远不会从其实现的接口继承任何注释。


37
此外,trutheality,搜索之前,我问过了,我想出了这个网页。恭喜,您现在已成为这些搜索结果的一部分。这就是为什么这个网站在这里。:)另外,您的答案比浏览该文档更为简洁。
Tustin2121

1
一个进一步推动这一问题的问题...如果框架基于注释找到该方法然后调用它,那么将调用该方法的哪个版本?子类的方法应该覆盖父类,但是反射调用会尊重它吗?
约翰B

1
如果我有Super abc = new Sub();foo对象的方法abc标记为@MyAnnotation("hello")
奥列格·瓦兹涅夫18/12/7

11

您已经找到答案了: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);
}

这不提供在任何超类实现中都找不到请求的注释的情况-在这种情况下,它将是抛出NoSuchMethodException,尽管null将是合法的返回值……
Uri Agassi 2015年

@UriAgassi这是设计使然。我认为JavaDoc明确了这一点。
圣塔利2015年

javadoc唯一清楚的NoSuchMethodException是抛出了a 。当方法不存在时,而不是在未找到注释应该引发这样的异常……它与原始实现不兼容(在这种情况下将返回)null
Uri Agassi


2

虽然所提出的问题的答案是JavaMethod.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;
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.