是否可以使用不同的实现反序列化 SerializedLambda?

is deserializing SerializedLambda with different implementations possible?

假设有一个 class A,其 lambda 函数名为 foo(为简单起见)。

据我了解,如果有客户端序列化此 foo(将序列化为 "SerializedLambda")并将其发送到服务器,则服务器也会将 class A 与名为 foo.

的 lambda 函数

现在,我的问题是,如果 A.foo 的实现在客户端和服务器之间不同怎么办? (假设 arg 类型和 return 类型相同) 服务器

  1. 根据自己的定义反序列化"SerializedLambda"没有错误

  2. 反序列化失败

鉴于 lambda 是如何动态创建的,并且 "SerializedLambda" 本身只包含签名、参数等而不是实际代码,我怀疑它是 1,但我是一个新手,需要了解更多关于它是如何工作的.

Lambda 表达式被编译成具有未指定名称的合成方法。可能还有其他未指定的微妙之处,例如捕获变量的方法参数顺序。此外,当lambda表达式访问this实例时,有两种选择,将其编译为实例方法或将其编译为static方法,像普通参数一样接收实例。

对于 lambda 表达式的结果行为,这没有区别。但序列化形式取决于这些细节,因此非常脆弱。您甚至不需要更改 class,使用不同的编译器重新编译它可能会更改这些细节。事实上,即使使用相同的编译器重新编译也可能会改变结果,例如当编译器的行为取决于一些具有迭代顺序随机化的哈希映射时。

在实践中,编译器供应商试图减少此类影响并产生稳定的结果,即使规范未强制要求也是如此。但是,当您更改 class 时,所有赌注都将取消。您可以在编译的 class 文件中轻松看到的一个方面是,编译器会根据源文件中出现的顺序向方法名称添加一个数字。插入另一个 lambda 表达式或删除一个可以更改所有后续 lambda 表达式的编号。

因此,更改后的 A class 可能与您的序列化 lambda 表达式不兼容,并且 可能发生的最好的事情 是在由于不匹配而反序列化。更糟糕的是,它可能 select 错误的 lambda 表达式,因为它恰好具有兼容的名称和签名组合。

一个更安全的构造是方法引用,因为它们引用实际的目标方法,它不受同一 class 中的其他 lambda 表达式或方法引用的影响。然而,并非每个方法引用都被编译为字节码级别的直接引用。在某些情况下,例如在引用可变参数方法或调用 super 方法或声明 class 与擦除类型不匹配的交集类型上的方法时,编译器可能会生成存根方法调用,类似于 lambda 表达式。所以还是要小心点。