考虑下一个代码:
interface A {
A setX(Object x);
A setY(Object y);
}
interface B extends A {
B setX(Object x);
}
如果您尝试使用B.class.getDeclaredMethods()
与jdk8您将获得以下方法:
public abstract B B. setx (java.lang.Object) andB.setX(java.lang.Object)
Javadoc说Class#getDeclaredMethods()
只返回声明的方法,那么为什么返回2个方法?如果有人解释了为什么第二个方法有'default'修饰符?
我应该发布一个bug报告吗?这个问题非常接近这个,但影响版本是jdk6和jdk7它工作得很好(返回单一方法)
我不会说这是一个bug。在javac编译B
接口时,增加了一个合成桥接方法,返回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,所以如果你不喜欢它,你可以基于此过滤掉它。
桥方法对于正确实现协变返回类型很有用,因为JVM不知道这个特性。它们对于分派对具有协变返回类型的方法的虚调用是必需的。Java 1.8中出现的新桥接方法有助于支持默认方法的协变返回类型。子接口可以定义setX
的默认实现,在这种情况下,需要自动生成的桥接方法来正确地调度对该实现的调用。