考虑下一个代码:
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,它工作正常(返回单个方法)
答案 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
的默认实现,在这种情况下,自动生成的桥接方法对于正确地将调用分派给该实现是必要的。