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



假设有一个名为foo的lambda函数的类a(为了简单起见(。

根据我的理解,如果有一个客户端正在序列化这个foo(它将被序列化为"SerializedLambda"(并将其发送到服务器,那么服务器也将具有名为foo的lambda函数的类a。

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

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

  2. 无法反序列化。

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

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

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

在实践中,编译器供应商试图减少这种影响并产生稳定的结果,即使在规范没有强制要求的情况下也是如此。但当你更改类时,所有的赌注都会落空。在编译后的类文件中,你可以很容易地看到一个方面,编译器会根据源文件中的出现顺序,在方法名中添加一个数字。插入另一个lambda表达式或删除其中一个可以更改所有后续lambda表达式的编号。

因此,更改后的A类可能与序列化的lambda表达式不兼容,最好的情况是由于不匹配而在反序列化过程中出现异常。更糟糕的是,它可能选择了错误的lambda表达式,因为它恰好具有兼容的名称和签名组合。

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

最新更新