Class#getDeclaredMethods()返回继承的方法

时间:2015-08-12 10:21:38

标签: java reflection java-8

考虑下一个代码:

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

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

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

公共摘要B B.setX(java.lang.Object) 公共默认A B.setX(java.lang.Object)

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

我应该发布一个bug报告吗? 这个问题非常接近to this one,但影响版本是jdk6,对于jdk7,它工作正常(返回单个方法)

1 个答案:

答案 0 :(得分:7)

我不会说这是一个错误。当您的B接口由javac编译时,它会添加一个合成桥接方法,该方法返回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()正确地返回它。对于这种额外的方法,isBridge()isSynthetic()调用将返回true,因此如果您不喜欢,可以根据此过滤掉它。

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