20

我想知道混合 jdk 1.5 和 1.6(Java 6)对象序列化(双向通信)是否安全。我搜索了 sun 关于这个问题的明确声明,但没有成功。因此,除了技术可行性之外,我还在寻找有关该问题的“官方”声明。

4

8 回答 8

16

序列化机制本身并没有改变。对于个别班级,这将取决于具体班级。如果一个类有一个 serialVersionUID 字段,这应该表示序列化兼容性。

就像是:

private static final long serialVersionUID = 8683452581122892189L;

如果未更改,则序列化版本是兼容的。对于 JDK 类,这是有保证的,但当然,在进行重大更改后总是可能忘记更新 serialVersionUID。

当 JDK 类不能保证兼容时,Javadoc 中通常会提到这一点。

警告:此类的序列化对象将与未来的 Swing 版本不兼容

于 2008-09-30T12:23:16.523 回答
3

1.5 和 1.6 中的序列化机制是兼容的。因此,在 1.5 和 1.6 上下文中编译/运行的相同代码可以交换序列化对象。两个 VM 实例是否具有相同/兼容的类版本(可能由 serialVersionUID 字段指示)是与 JDK 版本无关的不同问题。

如果您有一个可序列化的 Foo.java 并在 1.5 和 1.6 JDK/VM 中使用它,则 Foo 的序列化实例由一个 V 创建;可以被另一个反序列化。

于 2008-09-30T13:05:45.610 回答
2

在使用 Java 1.5 程序中的 ObjectOutputStream 对写入文件的序列化对象进行测试之后,然后在 Java 1.6 程序中使用 ObjectInputStream 运行读取,我可以说这没有任何问题。

于 2008-09-30T12:22:34.327 回答
2

我会很快补充一点,可以更改类但忘记更改serialVersionUID。所以“如果类定义了一个serialVersionUID,并且这没有改变,那么保证类是兼容的”是不正确的。相反,拥有相同的 serialVersionUID 是 API 承诺向后兼容性的方式。

于 2008-09-30T12:27:43.083 回答
2

除非另有说明,否则这应该是二进制兼容性的一部分。Swing 类在版本之间明确不兼容。如果您发现其他类有问题,请在bugs.sun.com上报告错误。

于 2008-09-30T12:31:13.120 回答
2

你读过Java 对象序列化规范吗?有一个关于版本控制的话题。还有一篇面向类实现者的文章:发现 Java 序列化 API 的秘密。每个 Java 版本都附有兼容性说明

来自 Java 6 的序列化规范:


目标是:

  • 通过以下方式支持在不同虚拟机中运行的类的不同版本之间的双向通信:
    • 定义一种机制,允许 JavaTM 类读取由同一类的旧版本编写的流。
    • 定义一种机制,允许 JavaTM 类编写旨在由同一类的旧版本读取的流。
  • 为持久性和 RMI 提供默认序列化。
  • 在简单的情况下执行良好并产生紧凑的流,以便 RMI 可以使用序列化。
  • 能够识别和加载与用于写入流的确切类匹配的类。
  • 保持非版本化类的开销较低。
  • 使用允许遍历流的流格式,而不必调用特定于保存在流中的对象的方法。

于 2008-09-30T12:49:43.013 回答
0

请注意,Java Beans 规范详细说明了一种与版本无关的序列化方法,该方法允许强大的向后兼容性。它还导致可读的“序列化”表单。事实上,使用该机制可以很容易地创建序列化对象。

查找XMLEncoderXMLDecoder类的文档。

我不一定会使用它来通过网络传递对象(尽管如果需要高性能,我也不会使用序列化),但它对于持久对象存储是非常宝贵的。

于 2008-09-30T23:06:47.680 回答
0

混合使用 Java 1.5 和 1.6 是不安全的。例如,我将一个 Java 1.5 对象序列化为一个文件,并尝试在 Java 1.6 中打开它,但它出现了以下错误。

java.io.InvalidClassException: javax.swing.JComponent; local class incompatible: stream classdesc serialVersionUID = 7917968344860800289, local class serialVersionUID = -1030230214076481435
    at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readArray(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readArray(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
于 2008-12-11T13:27:25.173 回答