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

2022-09-04 02:49:44

请考虑以下小示例:

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中的错误,或者为什么公共默认方法在这里重新出现?


答案 1

getDeclaredMethods()在这里表现正确,因为它准确地告诉你它在类中发现了什么。如果使用 Java 7 目标(或较旧的编译器)编译,则不会看到 与 Java 7 实现的输出没有区别。interfacegetDeclaredMethods()

编译器的行为不同。在 Java 8 中编译这样的子时,将生成一个桥接方法,该方法不会为 Java 7 目标生成,因为对于 Java 7 目标甚至不可能。interface

现在为接口生成桥接方法的原因是,您通常具有比接口更多的实现类,因此在接口中使用桥接方法可以避免将该桥接方法添加到每个实现中。此外,如果只有一个方法并且没有要实现的桥接方法,它使lambda类生成变得更加容易。defaultabstract

当层次结构需要桥接方法但没有提供 s 时,编译器必须使用 LambdaMetafactory.altMetafactory 而不是 LambdaMetafactory.metafactory 来生成代码,以指定所需的每个桥接方法。interfacedefault


答案 2

请原谅这种谩骂,但它必须在一个平行宇宙中,Javadoc的措辞足以解释这种行为:https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredMethods--。“所有声明的方法”的数组原来是“用户和StackOverflow上解释的一些底层实现细节的所有声明方法”的数组。更糟糕的是,我看到了一些关于注释的奇怪之处:我在应用注释时覆盖了泛型方法,并且返回的两个&方法都有注释,但只有一个具有正确的非泛型参数。因此,在我看来,这种实现细节部分违背了通过注释搜索方法的目的。abstractdefaultgetDeclaredMethods()abstract


推荐