【发布时间】:2026-01-24 10:00:01
【问题描述】:
我正在尝试使用 Java 8 中的新 Lambda,我正在寻找一种方法来使用 lambda 类的反射来获取 lambda 函数的返回类型。我对 lambda 实现通用超接口的情况特别感兴趣。在下面的代码示例中,MapFunction<F, T> 是泛型超接口,我正在寻找一种方法来找出绑定到泛型参数T 的类型。
虽然 Java 在编译器之后丢弃了大量泛型类型信息,但泛型超类和泛型超接口的子类(和匿名子类)确实保留了这些类型信息。通过反射,可以访问这些类型。在下面的示例中(案例1),反射告诉我MapFunction 的MyMapper 实现将java.lang.Integer 绑定到泛型类型参数T。
即使对于本身是泛型的子类,如果其他一些是已知的,也有一些方法可以找出绑定到泛型参数的内容。考虑以下示例中的 案例 2,IdentityMapper 其中F 和T 绑定到相同的类型。当我们知道这一点时,如果我们知道参数类型 T(在我的例子中我们知道),我们就知道类型 F。
现在的问题是,我如何才能为 Java 8 lambda 实现类似的功能?由于它们实际上不是通用超接口的常规子类,因此上述方法不起作用。
具体来说,我可以弄清楚parseLambda 将java.lang.Integer 绑定到T,而identityLambda 将相同的绑定到F 和T?
PS:理论上应该可以反编译 lambda 代码,然后使用嵌入式编译器(如 JDT)并利用其类型推断。我希望有一种更简单的方法来做到这一点;-)
/**
* The superinterface.
*/
public interface MapFunction<F, T> {
T map(F value);
}
/**
* Case 1: A non-generic subclass.
*/
public class MyMapper implements MapFunction<String, Integer> {
public Integer map(String value) {
return Integer.valueOf(value);
}
}
/**
* A generic subclass
*/
public class IdentityMapper<E> implements MapFunction<E, E> {
public E map(E value) {
return value;
}
}
/**
* Instantiation through lambda
*/
public MapFunction<String, Integer> parseLambda = (String str) -> { return Integer.valueOf(str); }
public MapFunction<E, E> identityLambda = (value) -> { return value; }
public static void main(String[] args)
{
// case 1
getReturnType(MyMapper.class); // -> returns java.lang.Integer
// case 2
getReturnTypeRelativeToParameter(IdentityMapper.class, String.class); // -> returns java.lang.String
}
private static Class<?> getReturnType(Class<?> implementingClass)
{
Type superType = implementingClass.getGenericInterfaces()[0];
if (superType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) superType;
return (Class<?>) parameterizedType.getActualTypeArguments()[1];
}
else return null;
}
private static Class<?> getReturnTypeRelativeToParameter(Class<?> implementingClass, Class<?> parameterType)
{
Type superType = implementingClass.getGenericInterfaces()[0];
if (superType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) superType;
TypeVariable<?> inputType = (TypeVariable<?>) parameterizedType.getActualTypeArguments()[0];
TypeVariable<?> returnType = (TypeVariable<?>) parameterizedType.getActualTypeArguments()[1];
if (inputType.getName().equals(returnType.getName())) {
return parameterType;
}
else {
// some logic that figures out composed return types
}
}
return null;
}
【问题讨论】:
-
小注释:
public MapFunction<String, Integer> parseLambda = (String str) -> { return Integer.valueOf(str); }可以写成public MapFunction<String, Integer> parseLambda = str -> Integer.valueOf(str);。 -
我认为不可能。似乎 Lambda 项目的作者出于某种原因试图阻止反射,因为堆栈跟踪没有提供有关方法名称的信息,甚至方法引用也没有通过反射提供方法名称。
-
@skiwi:我还没有编写任何 Java 8 代码,但我的理解是
public MapFunction<String, Integer> parseLambda = Integer::valueOf;实际上是等效的。 -
@JoachimSauer 没错
标签: java generics reflection lambda java-8