如何获取 Java 14 方法引用的 MethodInfo?

Ant*_*ias 0 java reflection lambda java-14

我本质上是在问与这个老问题相同的问题,但针对的是 Java 14 而不是 Java 8。为了避免回答者导航到老问题的麻烦,我将在这里重新表述。我想从引用的方法中获取函数的名称。下面的 Java 代码应该能让您明白:

public class Main
{
    public static void main(String[] args)
    {
       printMethodName(Main::main);
    }

    private static void printMethodName(Consumer<String[]> theFunc)
    {
        String funcName = // somehow get name from theFunc
        System.out.println(funcName)
    }
 }
Run Code Online (Sandbox Code Playgroud)

C# 中的等效内容是:

public class Main
{
    public static void Main()
    {
        var method = Main.Main;
        PrintMethodName(method)
    }

    private static void PrintMethodName(Action action)
    {
        Console.WriteLine(action.GetMethodInfo().Name);
    }
}
Run Code Online (Sandbox Code Playgroud)

根据老问题的公认答案,如果没有大量的工作,这在 Java 8 中是不可能的,例如这个解决方案。Java 14中有更优雅的解决方案吗?

Hol*_*ger 6

从方法引用获取方法信息从来都不是 JDK 开发者\xe2\x80\x99s 方面的目标,因此没有做出任何努力来改变这种情况。

\n

但是,您的链接中显示的方法可以简化。您可以在序列化时简单地拦截原始对象,而不是序列化信息、修补序列化数据并使用替换对象恢复信息SerializedLambda

\n

例如

\n
public class GetSerializedLambda extends ObjectOutputStream {\n    public static void main(String[] args) { // example case\n        var lambda = (Consumer<String[]>&Serializable)GetSerializedLambda::main;\n        SerializedLambda sl = GetSerializedLambda.get(lambda);\n        System.out.println(sl.getImplClass() + " " + sl.getImplMethodName());\n    }\n\n    private SerializedLambda info;\n\n    GetSerializedLambda() throws IOException {\n      super(OutputStream.nullOutputStream());\n      super.enableReplaceObject(true);\n    }\n\n    @Override protected Object replaceObject(Object obj) throws IOException {\n      if(obj instanceof SerializedLambda) {\n        info = (SerializedLambda)obj;\n        obj = null;\n      }\n      return obj;\n    }\n\n    public static SerializedLambda get(Object obj) {\n        try {\n            GetSerializedLambda getter = new GetSerializedLambda();\n            getter.writeObject(obj);\n            return getter.info;\n        } catch(IOException ex) {\n            throw new IllegalArgumentException("not a serializable lambda", ex);\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

将打印GetSerializedLambda main. 这里使用的唯一新功能是OutputStream.nullOutputStream()立即删除书面信息。在 JDK\xc2\xa011 之前,您可以写入 aByteArrayOutputStream并在操作后删除信息,但效率稍低。示例中也使用了var,但这与获取方法信息的实际操作无关。

\n

限制与 JDK\xc2\xa08 中的限制相同。它需要可序列化的方法引用。此外,不保证实现将直接映射到方法。例如,如果将 example\xe2\x80\x99s 声明更改为public static void main(String... args),它将打印类似于lambda$1使用 Eclipse 编译时的内容。当还将下一行更改为 时var lambda = (Consumer<String>&Serializable)GetSerializedLambda::main;,代码将始终打印合成方法名称,因为使用辅助方法是不可避免的。但在 的情况下javac,名称更像是lambda$main$f23f6912$1Eclipse\xe2\x80\x99s lambda$1

\n

换句话说,您可能会遇到令人惊讶的实现细节。不要依赖此类信息的可用性来编写应用程序。

\n