Class#getDeclaredMethods() returns 继承方法

Class#getDeclaredMethods() returns inherited methods

考虑下一个代码:

interface A {
    A setX(Object x);
    A setY(Object y);
}

interface B extends A {
    B setX(Object x);
}

如果您尝试将 B.class.getDeclaredMethods() 与 jdk8 一起使用 您将获得下一个方法:

public 摘要 B B.setX(java.lang.Object)public默认AB.setX(java.lang.Object)

Javadoc 说 Class#getDeclaredMethods() returns 只有 DECLARED 方法那么为什么返回 2 个方法?如果有人有解释那么为什么第二种方法有 'default' 修饰符?

我应该 post 报告错误吗? 这个问题非常接近 to this one 但影响版本是 jdk6 并且对于 jdk7 它工作正常(returns 单一方法)

我不会说这是一个错误。当您的 B 接口被 javac 编译时,它添加了一个合成桥接方法,即 returns A。您可以通过检查 javap 输出看到这一点:

$ javap -c B
Compiled from "B.java"
interface B extends A {
  public abstract B setX(java.lang.Object);

  public A setX(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokeinterface #1,  2          // InterfaceMethod     setX:(Ljava/lang/Object;)LB;
       7: areturn
}

在Java 1.7中当然没有这样的方法,因为在Java中不可能创建默认方法。因此,在 1.7 中编译时,您会得到以下内容:

$ javap -c B
Compiled from "B.java"
interface B extends A {
  public abstract B setX(java.lang.Object);
}

但是在 Java 1.8 中,这个额外的方法实际上是在字节码中声明的,所以 getDeclaredMethods() 正确地 return 了它。对于此附加方法,isBridge()isSynthetic() 调用将 return 为真,因此如果您不喜欢它,可以根据此过滤掉它。

桥接方法对于正确实现协变 return 类型很有用,因为 JVM 不知道此功能。它们是将虚拟调用分派到具有协变 return 类型的方法所必需的。 Java 1.8 中出现了新的桥接方法,有助于支持默认方法的协变 return 类型。子接口可以为 setX 定义一个默认实现,在这种情况下,自动生成的桥接方法将是正确分派对该实现的调用所必需的。