Java 7和Java 8中的getDeclaredMethods()行为不同

14

考虑下面这个简单的例子:

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中的一个漏洞吗?或者为什么公共默认方法在这里重新出现了?


3
我猜这可能与Java8接口默认方法的实现有关。 - user902383
2个回答

16

getDeclaredMethods()在这里表现正确,因为它准确地告诉您在类中找到了什么。如果您输入使用Java 7目标(或更早版本的编译器)编译的interface,则与Java 7实现的getDeclaredMethods()输出没有区别。

而是编译器行为不同。在Java 8中编译此类子interface时,将生成桥接方法,而对于Java 7目标,甚至无法生成桥接方法。

现在生成桥接方法的原因是您通常拥有比接口更多的实现类,因此在接口中具有default桥接方法可使您无需将该桥接方法添加到每个实现中。此外,如果只有一个abstract方法和没有桥接方法需要实现,则lambda类生成变得容易得多。

interface层次结构需要桥接方法但不提供default时,编译器必须使用LambdaMetafactory.altMetafactory而不是LambdaMetafactory.metafactory来指定所需的每个桥接方法。


0

抱歉有点沮丧,但这一定是在一个平行宇宙中,Javadoc 的措辞足以解释这种行为:https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredMethods--。一个“所有已声明方法”的数组实际上是一个“用户声明的所有方法和一些在 StackOverflow 上解释的底层实现细节的所有方法”的数组。更糟糕的是,我发现关于注释还有一些奇怪的事情:我正在覆盖一个通用方法并应用注释,而getDeclaredMethods()返回的abstractdefault方法都有注释,但只有abstract方法具有正确的非通用参数。因此,在我的看来,这个实现细节在某种程度上部分地破坏了通过注释搜索方法的目的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接