8

我正在尝试了解序列化如何与 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。因此,为了保证在不同的 java 编译器实现中具有一致的 serialVersionUID 值,可序列化的类必须声明一个显式的 serialVersionUID 值。还强烈建议显式 serialVersionUID 声明尽可能使用 private 修饰符,因为此类声明仅适用于立即声明的类——serialVersionUID 字段不能用作继承成员。数组类不能显式声明 serialVersionUID,因此它们始终具有默认计算值,但数组类无需匹配 serialVersionUID 值。

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

谢谢

4

1 回答 1

6

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

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

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

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

也不是lambdas的安全影响Serializable。一般来说,我建议避免使用它。

于 2015-04-14T10:29:16.700 回答