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

Java 是否可以使用不同的实现反序列化序列化DLAMBDA?,java,serialization,lambda,java-8,jvm,Java,Serialization,Lambda,Java 8,Jvm,假设有一个名为foo的lambda函数的类a(为了简单起见) 根据我的理解,如果有一个客户机序列化这个foo(它将被序列化为“SerializedLambda”)并将其发送到服务器,那么服务器也将具有名为foo的lambda函数的类a 现在,我的问题是,如果客户端和服务器之间A.foo的实现不同怎么办?(假设参数类型和返回类型相同) 服务器是否正常工作 根据自己的定义反序列化“SerializedLambda”,无错误 未能反序列化 鉴于lambda是如何动态创建的,而“SerializedLa

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

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

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

  • 根据自己的定义反序列化“SerializedLambda”,无错误

  • 未能反序列化


  • 鉴于lambda是如何动态创建的,而“SerializedLambda”本身只包含签名、参数等,而不是实际的代码,我怀疑它是1,但我是一个新手,需要进一步了解它的工作原理

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

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

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

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


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

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

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

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

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


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

    非常感谢@Holger。如果我从已编译类的内容为创建一个文件,并将其发送到服务器,在服务器上它将添加到(子类优先)类加载器的目录中,该怎么办?是否有可能使方法引用对所有情况都是安全的,还是对生成存根方法的情况没有帮助?我需要稳定性,因为我不能完全控制客户端的lambda。不清楚您想要实现什么。在一段代码中使用lambda表达式或方法引用的决定是一个简单的决定