1

在我的 TCP 服务器-客户端实现中,我的所有数据包都派生自实现 Serializable 的抽象基类。我将类转换为字节并通过套接字发送,接收器将这些字节反序列化并成功接收数据包。由于我缺乏关于序列化的知识,我不确定这是否可行,因为每个数据包类都有这样的警告:

可序列化类 CreateObjectPacket 未声明 long 类型的静态最终 serialVersionUID 字段

经过一番研究,我发现JVM使用这个UID来确保反序列化会成功(如果我没有错的话),所以为了摆脱这个警告,我让eclipse生成默认UID但是即使客户端和 Server 程序的 Packets 类完全相同,同一类的 UID 不同。它会在反序列化时引起任何问题,还是我应该手动设置这些 UID,如 1,2,3...?顺便说一句,我正在将传入的字节反序列化为超级抽象类 Packets,这也是一个问题还是我应该随意将其转换为派生的 Packets ?

编辑:最后,我的抽象 Packets 类有一个名为 fromByteArray 的静态方法用于反序列化:

public static Packets fromByteArray(byte[] arr) {

    ByteArrayInputStream bis = new ByteArrayInputStream(arr);
    ObjectInput in = null;
    try {
        in = new ObjectInputStream(bis);
        Packets o = (Packets) in.readObject();
        return o;
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        try {
            bis.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    return null;
}
4

1 回答 1

1

经过一番研究,我发现JVM使用这个UID来确保反序列化会成功

具体来说,它用于标识正在(反)序列化的对象的版本。当您允许自动分配 UID 时,如果要序列化的对象的内部结构发生变化,您的开发环境 (IDE) 应该分配一个新的 UID。这允许 JVM 识别您是否尝试将对象的一个​​版本反序列化为具有相同类名的对象的不同版本。

如果您自己分配版本 ID 并更改对象的内部结构(即成员字段),您也应该更改版本 ID。这样当您的类定义与您尝试从磁盘/网络反序列化的对象之间存在版本不匹配时,JVM 将能够捕捉到。

重新评论: http ://docs.oracle.com/javase/6/docs/platform/serialization/spec/version.html 5.6 影响序列化的类型更改 - 兼容与不兼容的更改

UID 的目的是向 JVM 指示对象的序列化结构是否发生了变化,使得对象的任何部分都无法可靠地反序列化。正如我在上面所写的,只有在对被序列化对象的结构进行不兼容的更改时才应该更改它。 如果客户端和服务器上的对象相同,如果客户端代码和服务器代码之间的 UID 不匹配,则反序列化对象可能会遇到问题。 您可以通过不定义 UID 来解决此问题,但请注意如果您的对象实现在未来发生变化时的后果。

于 2013-05-07T21:36:36.317 回答