考虑以下小例子:
package prv.rli.codetest;
import java.lang.reflect.Method;
public class BreakingInterfaces {
interface Base {
BaseFoo foo();
interface BaseFoo {
}
}
interface Derived extends Base {
DerivedFoo foo();
interface DerivedFoo extends BaseFoo {
}
}
public static void main(String[] args) {
dumpDeclaredMethods(Derived.class);
}
private static void dumpDeclaredMethods(Class<?> class1) {
System.out.println("---" + class1.getSimpleName() + "---");
Method[] methods = class1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("----------");
}
}
如果使用jdk1.7.0.55编译上述示例,则输出为:
---Derived---
public abstract BreakingInterfaces$Derived$DerivedFoo BreakingInterfaces$Derived.foo()
----------
但是当使用jdk1.8.0.25时,输出为:
---Derived---
public abstract prv.rli.codetest.BreakingInterfaces$Derived$DerivedFoo prv.rli.codetest.BreakingInterfaces$Derived.foo()
public default prv.rli.codetest.BreakingInterfaces$Base$BaseFoo prv.rli.codetest.BreakingInterfaces$Derived.foo()
----------
有没有人知道,这是jdk1.8.0.25中的错误还是为什么公共默认方法会在这里重现?
答案 0 :(得分:15)
getDeclaredMethods()
在这里表现正确,因为它告诉你它在课堂上发现了什么。如果您输入使用Java 7目标(或较旧的编译器)编译的interface
,您将看到getDeclaredMethods()
的Java 7实现的输出没有区别。
编译器的行为方式不同。在Java 8中编译这样的子interface
时,将生成一个不会为Java 7目标生成的桥接方法,因为它甚至不可能用于Java 7目标。
现在为接口生成桥接方法的原因是您通常拥有比接口更多的实现类,因此在接口中使用default
桥接方法可以避免将该桥接方法添加到每个实现。此外,如果只有一个abstract
方法并且没有实现桥接方法,它会使lambda类生成变得更加容易。
当interface
层次结构需要桥接方法但不提供default
时,编译器必须使用LambdaMetafactory.altMetafactory
生成代码,而不是LambdaMetafactory.metafactory
指定所需的每个桥接方法
答案 1 :(得分:0)
请原谅,但必须在并行的Universe中,Javadoc的措辞足以解释这种行为:https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredMethods--。数组“所有已声明的方法”实际上是“用户以及在StackOverflow 中解释的一些底层实现细节的所有声明的方法”的数组。更糟糕的是,我看到有关注释的一些怪异现象:我在应用注释时覆盖了通用方法,而abstract
返回的default
和getDeclaredMethods()
方法都具有注释,但是只有abstract
个具有正确的非通用参数。因此,在我看来,这种实现细节部分地破坏了通过注释搜索方法的目的。