好,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顯然,合成的函數接口驅動仍然只是一個正常的方法對象,你可以使用正常的反射來訪問。我只是想知道如何弄好包裹。 –