2

SerializedLambda 的签名如下:

SerializedLambda(类 captureClass,字符串功能接口类,字符串功能接口方法名,字符串功能接口方法签名,int implMethodKind,字符串 implClass,字符串 implMethodName,字符串 implMethodSignature,字符串实例化方法类型,对象 [] captureArgs)

现在,我可以看到捕获类是一个deserializeLambda

SerializedLambda 有一个 readResolve 方法,该方法在捕获类中查找名为 $deserializeLambda$(SerializedLambda) 的(可能是私有的)静态方法,并以自身作为第一个参数调用该方法

但我没有明白implClass它的用途。

获取包含实现方法的类的名称。

捕获类不就是有实现方法的吗?我尝试序列化 lambda 函数以查看这些字段包含哪些值,但它们具有相同的类。implClass和 和有什么不一样capturingClass

4

1 回答 1

3

使用当前的编译器,lambda 表达式总是被编译为同一个类中的合成方法,包含 lambda 表达式的主体。对于那些 lambda 表达式,捕获类始终与“implClass”相同。

但是对于不需要辅助方法的方法引用,“implClass”将是目标方法的声明类,而捕获类是包含方法引用的类。

例如,下面的例子

public class SerializedLambdaExample {
    public static void main(String[] args) throws ReflectiveOperationException {
        var hex = (IntFunction<String>&Serializable)Integer::toHexString;
        Method m = hex.getClass().getDeclaredMethod("writeReplace");
        m.setAccessible(true);
        SerializedLambda sl = (SerializedLambda)m.invoke(hex);
        System.out.println("cap: "+sl.getCapturingClass());
        System.out.println("target: "+sl.getImplClass()+" "+sl.getImplMethodName());
    }
}

使用 HotSpot/OpenJDK/javac 打印

cap: SerializedLambdaExample
target: java/lang/Integer toHexString

但请注意,确切的形式可能取决于实现。对于方法引用,某些结构,例如涉及可变参数或交集类型,可以使用类似于 lambda 表达式的辅助方法进行编译。理论上,包含一个简单的方法调用的 lambda 表达式可以像方法引用一样被编译,或者主体可以被放置到不同的类中,例如当类文件变得太大时,但这在当前编译器的实践中不会发生。

此外,不能保证该示例在所有运行时都有效。它仅用于演示目的。

于 2020-04-28T08:36:25.857 回答