猿问

Java 8 Lambdas上的反射类型推断

我正在尝试使用Java 8中的新Lambda,并且正在寻找一种在lambda类上使用反射来获取lambda函数的返回类型的方法。我对lambda实现通用超级接口的情况特别感兴趣。在下面的代码示例中,MapFunction<F, T>是通用超级接口,我正在寻找一种方法来找出绑定到通用参数的类型T。


尽管Java在编译器之后丢弃了许多泛型类型信息,但泛型超类和泛型超接口的子类(和匿名子类)确实保留了该类型信息。通过反射,可以访问这些类型。在下面的示例(案例1)中,反射告诉我,绑定的MyMapper实现MapFunction绑定java.lang.Integer到泛型type参数T。


即使对于本身是泛型的子类,如果已知其他一些子类,也可以通过某些方法找出绑定到泛型参数的内容。在下面的示例中考虑案例2,IdentityMapper其中F和T绑定到相同类型。当我们知道这一点时,F如果我们知道参数类型T(我们就知道),就知道类型。


现在的问题是,如何实现Java 8 lambda的类似功能?由于它们实际上不是通用超级接口的常规子类,因此上述方法不起作用。具体来说,我可以计算出的parseLambda结合java.lang.Integer来T,而identityLambda结合同向F和T?


PS:从理论上讲,应该可以反编译lambda代码,然后使用嵌入式编译器(如JDT)并利用其类型推断。我希望有一种更简单的方法可以做到这一点;-)


米脂
浏览 941回答 3
3回答

智慧大石

如何将lambda代码映射到接口实现的确切决定留给实际的运行时环境。原则上,实现相同原始接口的所有lambda都可以共享一个运行时类,就像这样MethodHandleProxies做一样。对特定的lambda使用不同的类是由实际实现执行的优化,LambdaMetafactory但不是旨在帮助调试或反射的功能。因此,即使您在lambda接口实现的实际运行时类中找到了更详细的信息,它也将是当前使用的运行时环境的产物,在不同的实现甚至您当前环境的其他版本中可能不可用。如果是lambda,则Serializable可以使用序列化的表单包含实例化接口类型的方法签名这一事实来一起混淆实际的类型变量值。

白猪掌柜的

参数化类型信息仅在运行时可用于绑定的代码元素-即专门编译成类型的代码元素。Lambda执行相同的操作,但是由于Lambda不支持方法而不是类型,因此没有类型可以捕获该信息。考虑以下:import java.util.Arrays;import java.util.function.Function;public class Erasure {&nbsp; &nbsp; static class RetainedFunction implements Function<Integer,String> {&nbsp; &nbsp; &nbsp; &nbsp; public String apply(Integer t) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return String.valueOf(t);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; public static void main(String[] args) throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; Function<Integer,String> f0 = new RetainedFunction();&nbsp; &nbsp; &nbsp; &nbsp; Function<Integer,String> f1 = new Function<Integer,String>() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public String apply(Integer t) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return String.valueOf(t);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; Function<Integer,String> f2 = String::valueOf;&nbsp; &nbsp; &nbsp; &nbsp; Function<Integer,String> f3 = i -> String.valueOf(i);&nbsp; &nbsp; &nbsp; &nbsp; for (Function<Integer,String> f : Arrays.asList(f0, f1, f2, f3)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(f.getClass().getMethod("apply", Integer.class).toString());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (NoSuchMethodException e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(f.getClass().getMethod("apply", Object.class).toString());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Arrays.toString(f.getClass().getGenericInterfaces()));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}f0并f1按照您的期望保留了它们的通用类型信息。但是由于它们是未绑定的方法,因此已被擦除为Function<Object,Object>,f2而f3不是。
随时随地看视频慕课网APP

相关分类

Java
我要回答