如何获取Java14方法引用的MethodInfo?
How to get the MethodInfo of a Java 14 method reference?
我基本上问的和 this old question 一样,但是 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)
}
}
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);
}
}
根据旧问题的公认答案,如果没有大量工作,这在 Java 8 中是不可能的,例如 this solution。 Java14有没有更优雅的方案?
从方法引用中获取方法信息从来都不是 JDK 开发人员的目标,因此没有努力改变这种情况。
但是,您 link 中显示的方法可以简化。无需序列化信息、修补序列化数据并使用替换对象恢复信息,您可以在序列化时简单地拦截原始 SerializedLambda
对象。
例如
public class GetSerializedLambda extends ObjectOutputStream {
public static void main(String[] args) { // example case
var lambda = (Consumer<String[]>&Serializable)GetSerializedLambda::main;
SerializedLambda sl = GetSerializedLambda.get(lambda);
System.out.println(sl.getImplClass() + " " + sl.getImplMethodName());
}
private SerializedLambda info;
GetSerializedLambda() throws IOException {
super(OutputStream.nullOutputStream());
super.enableReplaceObject(true);
}
@Override protected Object replaceObject(Object obj) throws IOException {
if(obj instanceof SerializedLambda) {
info = (SerializedLambda)obj;
obj = null;
}
return obj;
}
public static SerializedLambda get(Object obj) {
try {
GetSerializedLambda getter = new GetSerializedLambda();
getter.writeObject(obj);
return getter.info;
} catch(IOException ex) {
throw new IllegalArgumentException("not a serializable lambda", ex);
}
}
}
将打印 GetSerializedLambda main
。此处使用的唯一较新功能是 OutputStream.nullOutputStream()
以立即删除书面信息。在 JDK 11 之前,您可以写入 ByteArrayOutputStream
并在操作后删除信息,这只是效率稍低。例子中同样使用了var
,但这与实际获取方法信息的操作无关
限制与JDK 8相同。它需要一个可序列化的方法引用。此外,不保证实现将直接映射到方法。例如,如果您将示例的声明更改为 public static void main(String... args)
,则在使用 Eclipse 编译时它将打印类似 lambda
的内容。当还将下一行更改为 var lambda = (Consumer<String>&Serializable)GetSerializedLambda::main;
时,代码将始终打印合成方法名称,因为使用辅助方法是不可避免的。但是在 javac
的情况下,名称更像是 lambda$main$f23f6912
而不是 Eclipse 的 lambda
.
换句话说,您可能会遇到令人惊讶的实现细节。不要依赖此类信息的可用性来编写应用程序。
我基本上问的和 this old question 一样,但是 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)
}
}
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);
}
}
根据旧问题的公认答案,如果没有大量工作,这在 Java 8 中是不可能的,例如 this solution。 Java14有没有更优雅的方案?
从方法引用中获取方法信息从来都不是 JDK 开发人员的目标,因此没有努力改变这种情况。
但是,您 link 中显示的方法可以简化。无需序列化信息、修补序列化数据并使用替换对象恢复信息,您可以在序列化时简单地拦截原始 SerializedLambda
对象。
例如
public class GetSerializedLambda extends ObjectOutputStream {
public static void main(String[] args) { // example case
var lambda = (Consumer<String[]>&Serializable)GetSerializedLambda::main;
SerializedLambda sl = GetSerializedLambda.get(lambda);
System.out.println(sl.getImplClass() + " " + sl.getImplMethodName());
}
private SerializedLambda info;
GetSerializedLambda() throws IOException {
super(OutputStream.nullOutputStream());
super.enableReplaceObject(true);
}
@Override protected Object replaceObject(Object obj) throws IOException {
if(obj instanceof SerializedLambda) {
info = (SerializedLambda)obj;
obj = null;
}
return obj;
}
public static SerializedLambda get(Object obj) {
try {
GetSerializedLambda getter = new GetSerializedLambda();
getter.writeObject(obj);
return getter.info;
} catch(IOException ex) {
throw new IllegalArgumentException("not a serializable lambda", ex);
}
}
}
将打印 GetSerializedLambda main
。此处使用的唯一较新功能是 OutputStream.nullOutputStream()
以立即删除书面信息。在 JDK 11 之前,您可以写入 ByteArrayOutputStream
并在操作后删除信息,这只是效率稍低。例子中同样使用了var
,但这与实际获取方法信息的操作无关
限制与JDK 8相同。它需要一个可序列化的方法引用。此外,不保证实现将直接映射到方法。例如,如果您将示例的声明更改为 public static void main(String... args)
,则在使用 Eclipse 编译时它将打印类似 lambda
的内容。当还将下一行更改为 var lambda = (Consumer<String>&Serializable)GetSerializedLambda::main;
时,代码将始终打印合成方法名称,因为使用辅助方法是不可避免的。但是在 javac
的情况下,名称更像是 lambda$main$f23f6912
而不是 Eclipse 的 lambda
.
换句话说,您可能会遇到令人惊讶的实现细节。不要依赖此类信息的可用性来编写应用程序。