【问题标题】:How do Java method annotations work in conjunction with method overriding?Java 方法注释如何与方法覆盖结合使用?
【发布时间】:2012-04-10 03:04:24
【问题描述】:

我有一个父类 Parent 和一个子类 Child,定义如下:

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

如果我获得MethodChild::foo 的引用,childFoo.getAnnotation(MyAnnotation.class) 会给我@MyAnnotation 吗?还是null

我对注解如何或是否适用于 Java 继承更感兴趣。

【问题讨论】:

    标签: java inheritance annotations overriding


    【解决方案1】:

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

    【讨论】:

    • 另外,实话实说,在我问之前搜索过,我想出了这个页面。恭喜,您现在是这些搜索结果的一部分。这就是为什么这个网站在这里。 :) 此外,您的答案比查看该文档要简洁得多。
    • 一个问题来进一步说明......如果框架根据注释找到方法然后调用它,调用哪个版本的方法?子类的方法应该覆盖父类,但反射调用是否尊重它?
    • 如果我有Super abc = new Sub();,对象abc的方法foo会被标记为@MyAnnotation("hello")吗?
    【解决方案2】:

    您已经找到了答案: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 将是一个合法的返回值。 ..
    • @UriAgassi 这是设计使然。我认为 JavaDoc 说得很清楚。
    • javadoc 唯一明确的是抛出了NoSuchMethodException。它应该方法不存在时抛出这样的异常,而不是在找不到注解时......它与原始实现(在这种情况下将返回 null
    【解决方案3】:

    使用 Spring Core 你可以解决

    AnnotationUtils.java

    【讨论】:

      【解决方案4】:

      虽然问题的答案是 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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2021-05-24
        • 2020-01-30
        • 1970-01-01
        • 2017-07-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多