是否有可能(如何)在 Java 运行时获取方法引用的名称?

Joh*_*ohn 3 java reflection lambda java-8 method-reference

我最近使用了很多方法引用和 lambda,并且想知道在运行时是否可以打印以屏幕 lambda 的源(即它的名称),只是出于调试原因。我认为可以使用反射,通过在 getName() 中调用 getClass() 来实现,但我找不到用于查找原始源引用名称的方法。

我有一个功能界面,例如:

@FunctionalInterface
public interface FooInterface {
    // function etc etc irrelevant
    public void method();

    public default String getName() {
        // returns the name of the method reference which this is used to define
    }
}
Run Code Online (Sandbox Code Playgroud)

然后假设我希望测试运行该界面,并将功能界面的源代码打印到屏幕上。

public static void doStuff(FooInterface f) {
    // prints the lambda name that is used to create f
    System.out.println(f.getName());

    // runs the method itself
    f.method();
}
Run Code Online (Sandbox Code Playgroud)

所以如果我这样做:

doStuff(Foo::aMethodReference);
Run Code Online (Sandbox Code Playgroud)

它应该在屏幕上打印类似:“aMethodReference”的内容,这样我就可以知道在运行时正在运行哪些方法,以什么顺序运行等。

考虑到 lambda 不完全是对象,我很怀疑这是可能的,但是嘿,我想可能有一个解决方法。此外,eclipse调试工具只是说它是一个lambda,没有任何其他信息,lambda是否保留任何这些信息?或者在运行时全部丢失?

干杯。(如果有什么区别的话,我正在使用 JDK 11)

Fed*_*ner 5

正如你所说,你只需要这个用于调试目的,这里有一个技巧(即肮脏的黑客),它可以让你做你想做的事。

首先,您的功能接口必须是Serializable

@FunctionalInterface
public interface FooInterface extends Serializable {

    void method();
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用这个未记录的、依赖于内部实现且风险极高的代码来打印有关针对您的FooInterface功能接口的方法引用的一些信息:

@FunctionalInterface
public interface FooInterface extends Serializable {

    void method();

    default String getName() {
        try {
            Method writeReplace = this.getClass().getDeclaredMethod("writeReplace");
            writeReplace.setAccessible(true);
            SerializedLambda sl = (SerializedLambda) writeReplace.invoke(this);
            return sl.getImplClass() + "::" + sl.getImplMethodName();
        } catch (Exception e) {
            return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当你调用这个方法时:

doStuff(Foo::aMethodReference);
Run Code Online (Sandbox Code Playgroud)

您将看到以下输出:

package/to/the/class/Foo::aMethodReference
Run Code Online (Sandbox Code Playgroud)

注 1:我在Peter Lawrey 的这篇文章中看到了这种方法。

注2:我已经用openjdk version "11" 2018-09-25和进行了测试java version "1.8.0_192"