gpt4 book ai didi

Java:如何解析 lambda 参数的泛型类型?

转载 作者:太空狗 更新时间:2023-10-29 22:45:17 26 4
gpt4 key购买 nike

好吧,我们有 FunctionalInterface :

public interface Consumer<T> {

void accept(T t);

}

我可以像这样使用它:

.handle(Integer p -> System.out.println(p * 2));

我们如何解决实际的generic type我们代码中的那个 lambda 参数?

当我们将它用作内联实现时,提取 Integer 并不难来自该类的方法。

我错过了什么吗?或者只是 java 不支持 lambda 类?

为了更清洁:

那个 lambda 是用 MethodInvoker 包裹的(在提到的 handle 中),它在其 execute(Message<?> message) 中提取实际参数以供进一步的反射方法调用。在此之前,它使用 Spring 的 ConversionService 将提供的参数转换为目标参数.

方法handle在这种情况下,是在真正的应用程序工作之前进行一些配置。

不同的问题,但期待同一问题的解决方案:Java: get actual type of generic method with lambda parameter

最佳答案

目前这个问题是可以解决的,但只能以一种非常骇人听闻的方式解决,但让我先解释几件事:

当您编写 lambda 时,编译器会插入一条指向 LambdaMetafactory 的动态调用指令以及带有 lambda 主体的私有(private)静态合成方法。常量池中的合成方法和方法句柄都包含泛型类型(如果 lambda 使用该类型或如您的示例所示是显式的)。

现在在运行时调用 LambdaMetaFactory 并使用实现功能接口(interface)的 ASM 生成一个类,然后方法的主体调用私有(private)静态方法并传递任何参数。然后使用 Unsafe.defineAnonymousClass(参见 John Rose post)将其注入(inject)到原始类中,以便它可以访问私有(private)成员等。

不幸的是,生成的类不存储通用签名(它可以),因此您不能使用通常的反射方法来绕过删除

对于普通类,您可以使用 Class.getResource(ClassName + ".class") 检查字节码,但对于使用 Unsafe 定义的匿名类,您就不走运了.但是,您可以使用 JVM 参数让 LambdaMetaFactory 转储它们:

java -Djdk.internal.lambda.dumpProxyClasses=/some/folder

通过查看转储的类文件(使用javap -p -s -v),可以看出它确实调用了静态方法。但问题仍然是如何从 Java 本身中获取字节码。

不幸的是,这就是它被黑的地方:

使用反射,我们可以调用 Class.getConstantPool,然后访问 MethodRefInfo 以获取类型描述符。然后我们可以使用 ASM 来解析它并返回参数类型。把它们放在一起:

Method getConstantPool = Class.class.getDeclaredMethod("getConstantPool");
getConstantPool.setAccessible(true);
ConstantPool constantPool = (ConstantPool) getConstantPool.invoke(lambda.getClass());
String[] methodRefInfo = constantPool.getMemberRefInfoAt(constantPool.size() - 2);

int argumentIndex = 0;
String argumentType = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodRef[2])[argumentIndex].getClassName();
Class<?> type = (Class<?>) Class.forName(argumentType);

更新了 Jonathan 的建议

现在理想情况下,由 LambdaMetaFactory 生成的类应该存储通用类型签名(我可能会看看是否可以向 OpenJDK 提交补丁),但目前这是我们能做的最好的事情。上面的代码存在以下问题:

  • 它使用未记录的方法和类
  • 它极易受到 JDK 中代码更改的影响
  • 它不保留通用类型,因此如果您将 List 传递给 lambda,它会以 List 的形式出现

关于Java:如何解析 lambda 参数的泛型类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23863716/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com