我们有这个功能接口:
public interface Consumer<T> {
void accept(T t);
}
我可以这样使用它:
.handle(Integer p -> System.out.println(p * 2));
我们如何在代码中解析lambda参数的实际泛型类型?
当我们将它用作内联实现时,从该类的方法中提取Integer
并不困难。
我错过什么了吗?或者只是Java不支持lambda类?
更清楚地说:
lambda用MethodInvoker
Package (在提到的handle
中),在其execute(Message<?> message)
中提取实际参数用于进一步的反射方法调用。在此之前,它使用Spring的ConversionService
将提供的参数转换为目标参数。
在这种情况下,方法handle
是在真实的应用工作之前的一些配置。
不同的问题,但对同一问题的解决方案的期望:Java: get actual type of generic method with lambda parameter
2条答案
按热度按时间tcbh2hod1#
这是目前可以解决的,但只能以一种非常简单的方式解决,但让我首先解释几件事:
当你写一个lambda时,编译器插入一个指向LambdaMetafactory的动态调用指令和一个带有lambda主体的私有静态合成方法。常量池中的合成方法和方法句柄都包含泛型类型(如果lambda使用该类型或像您的示例中那样显式)。
现在,在运行时调用
LambdaMetaFactory
,并使用ASM生成一个类,该类实现函数接口和方法体,然后使用传递的任何参数调用私有静态方法。然后使用Unsafe.defineAnonymousClass
(参见John Rose post)将其注入到原始类中,以便它可以访问私有成员等。不幸的是,生成的类没有存储通用签名(它可以),因此您不能使用通常的反射方法来避免擦除
对于一个普通的类,你可以使用
Class.getResource(ClassName + ".class")
检查字节码,但是对于使用Unsafe
定义的匿名类,你就不走运了。但是,您可以使用JVM参数使LambdaMetaFactory
转储它们:通过查看转储的类文件(使用
javap -p -s -v
),可以看到它确实调用了静态方法。但问题仍然是如何从Java本身中获取字节码。不幸的是,这是它得到黑客:
使用反射,我们可以调用
Class.getConstantPool
,然后访问MethodRefInfo来获取类型描述符。然后我们可以使用ASM来解析它并返回参数类型。把这些放在一起:更新了Jonathan的建议
现在,理想情况下,
LambdaMetaFactory
生成的类应该存储泛型类型签名(我可能会看看是否可以向OpenJDK提交一个补丁),但目前这是我们能做的最好的。上面的代码有以下问题:oaxa6hgo2#
使用
TypeRef
Package lambda表达式。输出: