好,lambda表达式被脱到编译过程中的方法和,只要他们不占领this
(不访问非static
会员突破),这些方法将是static
。棘手的部分是到达这些方法,因为功能接口实例和其目标方法之间没有可检查的连接。
为了说明这一点,在这里最简单的情况:
public class LambdaToMethod {
public static void legacyCaller(Object arg, Method m) {
System.out.println("calling Method \""+m.getName()+"\" reflectively");
try {
m.invoke(null, arg);
} catch(ReflectiveOperationException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) throws URISyntaxException
{
Consumer<String> consumer=s -> System.out.println("lambda called with "+s);
for(Method m: LambdaToMethod.class.getDeclaredMethods())
if(m.isSynthetic() && m.getName().contains("lambda")) {
legacyCaller("a string", m);
break;
}
}
}
这工作顺利,因为这里仅有一个lambda表达式,因此,一个候选方法。该方法的名称是编译器特定的,可能含有一些序列号或哈希码等
在组装机是使lambda表达式序列化和检查其序列化形式:
static Method lambdaToMethod(Serializable lambda) {
for(Class<?> cl=lambda.getClass(); cl!=null; cl=cl.getSuperclass()) try {
Method m=cl.getDeclaredMethod("writeReplace");
m.setAccessible(true);
try {
SerializedLambda sl=(SerializedLambda)m.invoke(lambda);
return LambdaToMethod.class.getDeclaredMethod(sl.getImplMethodName(),
MethodType.fromMethodDescriptorString(sl.getImplMethodSignature(),
LambdaToMethod.class.getClassLoader()).parameterArray());
} catch(ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
} catch(NoSuchMethodException ex){}
throw new AssertionError();
}
public static void main(String[] args)
{
legacyCaller("a string", lambdaToMethod((Consumer<String>&Serializable)
s -> System.out.println("first lambda called with "+s)));
legacyCaller("a string", lambdaToMethod((Consumer<String>&Serializable)
s -> System.out.println("second lambda called with "+s)));
}
这工作,但,可串行化的lambda表达式价格很高。
最简单的解决办法是将注释添加到lambda表达式的参数遍历方法时被发现,但是,目前,javac
不存储标注正确,也看到this question这个话题。
但你也可以考虑只创建普通static
方法持代码,而不是一个lambda表达式。为一个方法获得一个Method
对象是直接的,你仍然可以使用方法引用创建一个功能接口实例...
没有什么像lambda表达式的'方法'实例。 Lambda是匿名函数的语法糖。他们为你提供了一个实例,但是你不能从中得到一个方法 – Jatin
@Jatin显然,合成的函数接口驱动仍然只是一个正常的方法对象,你可以使用正常的反射来访问。我只是想知道如何弄好包裹。 –