bil*_*.cn 11 reflection lambda java-8
(这很难搜索,因为结果都是关于"方法参考")
我想获得一个Methodlambda表达式的实例,以便与基于遗留反射的API一起使用.应该包含clousure,因此调用thatMethod.invoke(null, ...)应该与调用lambda具有相同的效果.
我看过MethodHandles.Lookup,但它似乎只与逆向变换有关.但我想这种bind方法可能有助于包括clousure?
编辑:
说我有lambda experssion:
Function<String, String> sayHello = name -> "Hello, " + name;
Run Code Online (Sandbox Code Playgroud)
我有一个具有API 的遗留框架(SpEL)
registerFunction(String name, Method method)
Run Code Online (Sandbox Code Playgroud)
这将调用Method没有this参数的给定(即假定方法是静态的).所以我需要得到一个Method包含lambda逻辑+ clousure数据的特殊实例.
ass*_*ias 10
如果你找不到优雅的方式,这就是丑陋的方式(Ideone).涉及反思时的常见警告:未来版本可能会中断等
public static void main(String[] args) throws Exception {
Function<String, String> sayHello = name -> "Hello, " + name;
Method m = getMethodFromLambda(sayHello);
registerFunction("World", m);
}
static void registerFunction(String name, Method method) throws Exception {
String result = (String) method.invoke(null, name);
System.out.println("result = " + result);
}
private static Method getMethodFromLambda(Function<String, String> lambda) throws Exception {
Constructor<?> c = Method.class.getDeclaredConstructors()[0];
c.setAccessible(true);
Method m = (Method) c.newInstance(null, null, null, null, null, 0, 0, null, null, null, null);
m.setAccessible(true); //sets override field to true
//m.methodAccessor = new LambdaAccessor(...)
Field ma = Method.class.getDeclaredField("methodAccessor");
ma.setAccessible(true);
ma.set(m, new LambdaAccessor(array -> lambda.apply((String) array[0])));
return m;
}
static class LambdaAccessor implements MethodAccessor {
private final Function<Object[], Object> lambda;
public LambdaAccessor(Function<Object[], Object> lambda) {
this.lambda = lambda;
}
@Override public Object invoke(Object o, Object[] os) {
return lambda.apply(os);
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于只有一个lambda表达式,因此只有一种候选方法,因此这种方法可以顺利进行。该方法的名称特定于编译器,并且可能包含一些序列号或哈希码等。
在kludge上是使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)));
}
Run Code Online (Sandbox Code Playgroud)
这可以工作,但是可序列化的lambda价格很高。
最简单的解决方案是在迭代方法时将注释添加到要查找的lambda表达式的参数,但是,当前,javac该注释存储不正确,另请参阅关于此主题的此问题。
但是您也可以考虑只创建static保存代码的普通方法,而不是lambda表达式。Method为方法获取对象很简单,您仍然可以使用方法引用从它们中创建功能接口实例…
| 归档时间: |
|
| 查看次数: |
4357 次 |
| 最近记录: |