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

标签 java serialization lambda java-8 jvm

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

根据我的理解,如果有一个客户端序列化这个 foo (它将被序列化为“SerializedLambda”)并将其发送到服务器,那么服务器也会拥有带有名为 foo 的 lambda 函数的 A 类。

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

  1. 根据“SerializedLambda”自己的定义反序列化,不会出现错误。

  2. 反序列化失败。

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

最佳答案

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

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

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

因此,更改后的 A 类可能与序列化的 lambda 表达式不兼容,而可能发生的最好的事情是反序列化期间由于不匹配而出现异常。更糟糕的是,它可能会选择错误的 lambda 表达式,因为它碰巧具有兼容的名称和签名组合。

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

关于java - 是否可以使用不同的实现来反序列化 SerializedLambda?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61452242/

相关文章:

java - JPanel SetPreferedSize 与实际大小不匹配

java - 如何在 Spring boot 中读取未映射到 @RequestBody 模型对象的附加 JSON 属性

json - Knockout JS - 将类序列化为 JSON

c# - 启动新线程时抛出IndexOutOfRangeException

lambda - 故障保护与Fallback() : why kotlin compiler fails to infer lambda type?

java - 多行 lambda 比较器

java - 将对象克隆到数组列表中,java

c# - 如何对 Object 类型的属性使用 ShouldSerialize[MemberName]() 方法?

symfony - 如何在 Symfony 4 中使用 datetimeNormalizer?

c# - 为什么在 lambda 表达式中使用迭代变量不好