【问题标题】:Interface method´s annotations are inherited in Java 7 but not in Java 8接口方法的注解在 Java 7 中继承,但在 Java 8 中没有
【发布时间】:2017-05-23 13:54:19
【问题描述】:

我正在从 Java 7 迁移到 Java 8,并且遇到了这种语言变化。

我有一个带有注释方法的超级接口:

public interface SuperInterface {

  @X
  SuperInterface getSomething();
}

我有一个带有相同注释方法但返回子接口的子接口:

public interface SubInterface extends SuperInterface {

  @X
  SubInterface getSomething();
}

当我运行这个测试时,它在 Java 8 中失败,但在 Java 7 中没有:

import java.lang.reflect.Method;

public class Test {

  public static void main(String[] args) {
    final Method[] methods = SubInterface.class.getMethods();
    for (Method method : methods) {
      if (method.getAnnotations().length == 0) {
        throw new RuntimeException("No annotations found for " + method);
      }
    }
  }
}

接口方法的注解在 Java 7 中被继承,但在 Java 8 中没有,是真的吗?

@X 定义为:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface X {  
}

【问题讨论】:

  • 没有javac/java 1.8.0_121 的复制。我确实在eclipse中得到了错误。您使用的是哪个 java8 编译器?
  • 为什么返回一个SuperInterface 一个default 方法?在 Java7 中,它们都是 abstract,但在 Java8 中,它们是 default
  • @Shadov 是的,在 Java 8 中:公共默认 SuperInterface test.SubInterface.getSomething() 但在 Java 7 中:公共抽象 test.SuperInterface SuperInterface.getSomething()
  • 好吧,您实际上是在 SubInterface 中覆盖了方法 getSomething(),因此,根本没有继承方法。可以看到 SuperInterface 带有反射的擦除方法是 Java 8 之前的一个技术弱点。在 Java 8 中(使用javac),您看不到任何继承方法,而是两种方法,覆盖方法和桥接方法。 bridge 方法将具有 overriding 方法的注解,但不会继承 SuperInterface.getSomething() 方法的注解。

标签: java eclipse java-8 java-7 eclipse-jdt


【解决方案1】:

this 称,据我所知,它应该至少 使用 java-8 的 build 94。因此这是一个 Eclipse 编译器错误(我无法使用 javac 重现它)。

您在这里使用协方差,因此将生成两种方法(一种是桥):

 for (Method method : methods) {
        if (method.getAnnotations().length == 0) {
            System.out.println("Not present " + method.getName() + " isBridge? " + method.isBridge());
        } else {
            System.out.println("Present :" + method.getName() + " isBridge? " + method.isBridge());
        }
    }

但这又应该可以工作,因为错误清楚地表明:具有运行时保留的注释应该由 javac 复制以桥接方法

输出javac:

Present :getSomething isBridge? false
Present :getSomething isBridge? true

输出eclipse compiler:

Present :getSomething isBridge? false
Not present getSomething isBridge? true

【讨论】:

  • OMG,我测试了beta132和update121之间的所有JDK,得出的结论是无法复制,但我应该测试过beta94之前的版本……
  • @Holger I tested all JDKs between beta132 and update121 你的机器上都有吗?这真是太棒了!
  • 也许“全部”有点委婉。我有所有相关的更新,可以得出结论,通过它们的代码也可以与(未发布的)中间版本一起使用。更新编号系统使它看起来比实际要多得多。更有趣的部分是脚本,它遍历所有脚本以编译和运行测试程序……
  • @Holger 这是自从你发表评论以来我唯一能想到的!脚本!!!我立刻想到尝试为自己创造这样的东西
【解决方案2】:

对于 Eclipse ecj 编译器,这看起来像引用 JDK 6695379 的 Eclipse 错误495396

它被标记为针对 4.7,但 4.7 已经处于候选发布状态,所以我猜它没有进入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 2011-12-07
    • 2015-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多