从简单的角度来看,lambda表达式被编译为static
方法,因为它们不捕获this
(即不访问实例成员)。
public class App {
public static void foo(){
Consumer<Integer> c1 = n -> {};
Consumer<Integer> c2 = n -> {};
}
public static void main(String [] args) {
Supplier<String> sup1 = () -> "I am sup1";
Supplier<String> sup2 = () -> "I am sup2";
Supplier<String> sup3 = () -> "I am sup3";
Stream.of(App.class.getDeclaredMethods()).forEach(System.out::println);
}
}
运行上一个示例并使用javap
工具检查生成的字节码,我们可以看到变量引用的lambdas c1
,c2
,sup1
,{{1 },sup2
被编译为名称为
sup3
lambda$foo$0
lambda$foo$1
lambda$main$2
lambda$main$3
但是,如果我们为这些变量引用的每个对象打印lambda$main$4
(getClass()
,c1
,c2
,sup1
,{{1}我们将分别获得:
sup2
sup3
class App$$Lambda$5/1705736037
class App$$Lambda$6/455659002
class App$$Lambda$1/791452441
那么,我们如何才能使运行时类名称和lambdas产生的方法名称之间的对应关系?
更新
以下重复问题中提到的解决方案都没有帮助我解决我在问题中提出的问题:
我找到的唯一方法是将@Holger的解决方案从其答案(不是可接受的答案)改为问题Java 8: convert lambda to a Method instance with clousure included。但是,在我的情况下,我只是在寻找方法的名称而不是class App$$Lambda$2/531885035
对象。因此,将lambdaToMethod()
调整为以下class App$$Lambda$3/1418481495
我得到了一个解决方案:
Method
现在,必须按照@Holger answer中的描述将示例的lambdas强制转换为methodNameFromLambda()
或static String methodNameFromLambda(Serializable lambda) {
try {
Method m = lambda.getClass().getDeclaredMethod("writeReplace");
m.setAccessible(true);
SerializedLambda sl=(SerializedLambda)m.invoke(lambda);
return sl.getImplMethodName();
} catch(ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
。
我不知道这个解决方案是否正确,但它适用于我的示例以及我正在处理的案例。
答案 0 :(得分:3)
这可能会因版本而异 - 没有说明确切名称的说明 - 并且故意;以防止可能找到与这些名称有关的聪明事情的代码。