假设有一个类 A,其 lambda 函数名为 foo(为了简单起见)。
根据我的理解,如果有一个客户端序列化这个 foo (它将被序列化为“SerializedLambda”)并将其发送到服务器,那么服务器也会拥有带有名为 foo 的 lambda 函数的 A 类。
现在,我的问题是,如果 A.foo 的实现在客户端和服务器之间不同怎么办? (假设参数类型和返回类型相同) 服务器是否有
根据“SerializedLambda”自己的定义反序列化,不会出现错误。
反序列化失败。
考虑到 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/