【问题标题】:serialized lambda and no serialVersionUID?序列化的 lambda 并且没有 serialVersionUID?
【发布时间】:2015-06-19 09:15:55
【问题描述】:

我正在尝试了解序列化如何与 Java 及其最新版本一起使用。我正在尝试像这样序列化一个 lambda:

Runnable r = (Runnable & Serializable)() -> {System.out.println("This is a test");};

但我注意到我没有关于缺少 serialVersionUID 变量的警告。正常吗?

我知道它将在运行时生成,但强烈建议定义它:https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html

如果一个可序列化的类没有显式声明一个 serialVersionUID,那么序列化运行时将计算一个 基于各个方面的该类的默认 serialVersionUID 值 类的,如 Java(TM) 对象序列化中所述 规格。但是,强烈建议所有 可序列化的类显式声明 serialVersionUID 值,因为 默认的 serialVersionUID 计算对类高度敏感 细节可能因编译器实现而异,并且可以 因此导致意外的 InvalidClassExceptions 在 反序列化。因此,要保证一致的serialVersionUID 跨不同 java 编译器实现的值,一个可序列化的 类必须声明一个显式的 serialVersionUID 值。也是 强烈建议显式 serialVersionUID 声明使用 可能的情况下使用私有修饰符,因为此类声明仅适用于 立即声明类--serialVersionUID 字段不是 作为继承成员有用。数组类不能显式声明 serialVersionUID,所以它们总是有默认的计算值,但是 匹配 serialVersionUID 值的要求被放弃 数组类。

我该怎么办?如何在我的 Lambda 中定义它?

谢谢

【问题讨论】:

  • 由于缺少定义类,似乎无法声明字段serialVersionUID。这直接引出了下一个问题:为什么 lambda 应该是可序列化的?它没有字段,因此没有数据!
  • @Seelenvirtuose 序列化的 lambda 包含在评估 lambda 时捕获的值。如果使用不同的捕获值对 lambda 进行多次评估,则体现 lambda 的对象将有所不同,它们的序列化表示也会有所不同。
  • @StuartMarks 显然我想得还不够远。感谢您指出了这一点。事实上,它帮助我改变(建立?)我的想法。

标签: java serialization lambda java-8 serialversionuid


【解决方案1】:

serialVersionUID 仅与生成 stream identifier 的类相关。如果可序列化类具有返回不同类的替代对象的writeReplace() 方法(也在Serializable documentation 中描述),则情况并非如此,因为这种表示与原始类完全分离。这就是可序列化 lambda 实例所发生的情况,请参阅SerializedLambda

可序列化 lambda 的实现者(例如编译器或语言运行时库)应确保实例正确反序列化。这样做的一种方法是确保writeReplace 方法返回SerializedLambda 的实例,而不是允许继续进行默认序列化。

所以它是SerializedLambda 的一个实例,它最终出现在流中,因此该类有责任拥有一个稳定的序列化表示。不幸的是,这并不能保护您免受可能的不兼容性。

在反序列化时,将调用定义 lambda 表达式的类的合成方法(与 thisthis answer 相比),这将拒绝与该类中现有的 lambda 表达式定义不匹配的反序列化尝试,而匹配可能取决于 lambda 定义的微妙方面。请注意,即使使用 Eclipse 而不是 javac 重新编译定义类也可能会破坏序列化兼容性。

也不是security impacts of Serializable lambdas。一般来说,我建议避免使用它。

【讨论】:

    猜你喜欢
    • 2017-07-15
    • 2017-07-29
    • 2015-04-21
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 2012-12-04
    相关资源
    最近更新 更多