java - SerialVersionUID 对于外部化类真的有意义吗?

标签 java serialization

我已经阅读了一些有关 Java 如何控制对可序列化对象的访问的问题和讨论。我的问题是关于外部化对象以及为什么serialVersionUID应该影响它。我期望答案是“因为Externalized接口(interface)扩展了Serialized接口(interface)”,因此该字段是必需的。诚然,我的回答有些烦人,“为什么Externalized要扩展Serialized?”有两个原因。

第一个原因很简单,要实现外部化,需要重写 readExternal 和 writeExternal 以将数据传入和传出类实例。

第二个有点复杂,但情况是这样的:

我的新 Foo 类当前包含两个 String 字段,但我预计它会随着我的函数的增长而增长,因为用户更改了一些需求。如果我声明 Foo 是可序列化的,我可以毫无问题地将对象写入文件,直到我需要更新类以添加另一个字段。现在我不能在一个程序中拥有两个版本的 Foo 对象,因此现有 Foo 对象的任何文件都是垃圾,如果不编写一个函数读取当前 Foo 文件并将其作为文本写出来,则无法对其进行处理,然后另一个函数用于读取文本、计算新的 Foo 字段并将其写入序列化表单的更新版本。

所以我的想法是我应该将 Foo 声明为可外部化,添加一个内部版本字段,该字段是通过 writeExternal 函数写入的第一个字段,以便 readExternal 函数首先读取该字段,然后可以根据该值控制其余字段。

将两个版本并排进行比较:

enter code
    Original version                                          Updated version

 1  public class Foo implements Externalizable {              public class Foo implements Externalizable {
 2                        
 3    static final private long serialVersionUID=????;          static final private long serialVersionUID=????;
 4    static final private long VER00=0;                        static final private long VER00=0;
 5                                                     *****    static final private long VER01=1;
 6
 7    private int fooVer=0;                                     private int fooVer=1;
 8    public String dsn="", lst="";                    *****    public String dsn="", lst="", ext="";
 9    public String getDsn() {return dsn;}                      public String getDsn() {return dsn;}
10    public String getLst() {return lst;}                      public String getLst() {return lst;}
11                                                     *****    public String getExt() {return ext;}
12    public void putDsn(String s) {dsn=s;}                     public void putDsn(String s) {dsn=s;}
13    public void putLst(String s) {lst=s;}                     public void putLst(String s) {lst=s;}
14                                                     *****    public void putExt(String s) {ext=s;}
15                        
16    public Foo() {super();}                                   public Foo() {super();}
17                        
18    @Override                                                @Override
19    public void readExternal(ObjectInput in)                 public void readExternal(ObjectInput in)
20      throws IOException, ClassNotFoundException {             throws IOException, ClassNotFoundException {
21      this.fooVer=in.readLong();                               this.fooVer=in.readLong();
22                                                     *****     if (this.fooVer==VER01) {
23                                                     *****       this.dsn=(String) in.readObject();
24                                                     *****       this.lst=(String) in.readObject();
25                                                     *****       this.ext=(String) in.readObject();
26                                                     *****       return;
27                                                     *****     }
28      if (this.fooVer==VER00) {                                if (this.fooVer==VER00) {
29        this.dsn=(String) in.readObject();                       this.dsn=(String) in.readObject();
30        this.lst=(String) in.readObject();                       this.lst=(String) in.readObject();
31                                                     *****       this.ext="no ext available";
32        return;                                                  return;
33      }                                                        }
34      throw new ClassNotFoundException                         throw new ClassNotFoundException
35        ("unsupported fooVer "+this.fooVer);                     ("unsupported fooVer "+this.fooVer);
36    }                                                        }
37                        
38    @Override                                                @Override
39    public void writeExternal(ObjectOutput out)              public void writeExternal(ObjectOutput out)
40      throws IOException {                                     throws IOException {
41      fooVer=VER00;                                  *****     fooVer=VER01;
42      out.writeLong(fooVer);                                   out.writeLong(fooVer);
43      out.writeObject(dsn);                                    out.writeObject(dsn);
44      out.writeObject(lst);                                    out.writeObject(lst);
45                                                     *****     out.writeObject(ext);
46    }                                                        }
47  }                                                        }

here

由于 Foo 控制外部化,我应该能够让值不同,比如 0 和 1,并且仍然正确处理记录,但是如果我用旧值写入并在第一次读取时用新值读取,我获取 InvalidClassException,其中消息为: “本地类不兼容:流classdesc serialVersionUID = 0,本地类serialVersionUID = 1”。

因此,据我所知,无论我多么小心,我都必须简单地为serialVersionUID选择一个值,并且永远不要更改它,除非我想丢失所有早期数据。因此,我基本上正在做很多额外的工作,以防止序列化使用serialVersionUID 来执行其预期的操作。 :/

我错过了什么吗?

最佳答案

I have to simply pick a value for the serialVersionUID and never change it unless I want to lose all earlier data

这是正确的,无论您实现 Ssrialized 还是 Externalized,它都适用。

关于java - SerialVersionUID 对于外部化类真的有意义吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48250895/

相关文章:

c# - Microsoft.WindowsAzure.Storage.Table.TableEntity 未使用 Storage 4.3.0.0 标记为可序列化

java - 如何在 protobuf 消息中添加一个 int 数组

jQuery 序列化并返回 JSON 字符串

java - Selenium:比较复选框中的两个字符串数组

java - oracle数据库中表不存在则自动创建

java - 写入文本文件

java - 持久化的序列化缺点

c# - 将不可序列化的类转换为字节数组

java - Spring - 应用程序初始化两次?

java - Java发送邮件的问题