getDeclaredMethods()在Java 7与Java 8中的表现不同

时间:2014-11-19 09:44:15

标签: java java-8

考虑以下小例子:

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中的错误还是为什么公共默认方法会在这里重现?

2 个答案:

答案 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返回的defaultgetDeclaredMethods()方法都具有注释,但是只有abstract个具有正确的非通用参数。因此,在我看来,这种实现细节部分地破坏了通过注释搜索方法的目的。