serialVerionUID对外化类有意义吗?

时间:2018-01-14 15:01:45

标签: java serialization

我已经阅读了几个关于Java如何控制对Serializable对象的访问的问题和讨论。我的问题是关于Externalizable对象以及serialVersionUID 应该影响它的原因。我期待答案将是“因为Externalizable接口扩展了Serializable接口”,因此该字段是必需的。我承认有点恼人的回答是“为什么Externalizable会扩展Serializable?”有两个原因。

第一个原因是,实现外化需要覆盖readExternal和writeExternal以将数据传入和传出类实例。

第二个有点复杂,但情况如下:

我的新Foo类目前包含两个String字段,但我希望它随着我的函数增长而增长,因为用户改变了一些要求。如果我将Foo声明为Serializable,我可以将对象写入文件,没有问题,直到我需要更新类以添加另一个字段。现在我不能在一个程序中有两个版本的Foo对象,所以现有的Foo对象的任何文件都是垃圾,如果不写一个函数读取当前的Foo文件并将其作为文本写出来就无法处理,然后另一个读取文本的函数,重新定义新的Foo字段并将其写为序列化表单的更新版本。

所以我的想法是我应该将Foo声明为Externalizable,添加一个内部版本字段,这是通过writeExternal函数编写的第一个字段,因此readExternal函数首先读取该字段,其余部分可以根据该值进行控制。 / p>

将两个版本放在一边进行比较:

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,并且仍然正确处理记录,但如果我用旧值写入并在第一次读取时使用new读取得到一个InvalidClassException消息是:   “本地类不兼容:stream classdesc serialVersionUID = 0,local class serialVersionUID = 1”。

所以从我所知道的,不管我多么小心,我必须简单地为serialVersionUID选择一个值,除非我想丢失所有早期数据,否则永远不会改变它。因此,我基本上正在做很多额外的工作,以防止序列化使用serialVersionUID来做它想要做的事情。 :/

我错过了什么吗?

1 个答案:

答案 0 :(得分:2)

  

我必须简单地为serialVersionUID选择一个值,除非我想丢失所有早期数据,否则永远不要更改它

这是正确的,无论您是实施$username = $_SESSION['username']; $target_dir = "images/uploads/"; $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]); $uploadOk = 1; $imageFileType = pathinfo($target_file,PATHINFO_EXTENSION); // Check if image file is a actual image or fake image if(isset($_POST["change"])) { hash_file('sha256', $sql); move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file); $sql = "UPDATE users SET userPic = '".$_FILES['fileToUpload']['name']."' WHERE username = '" . $username . "'"; $check = $conn->query($sql); if($check !== false) { echo "<a href = profile.php> Profile pciture has been changed </a>" . $check["mime"] . "."; $uploadOk = 1; } else { echo "File is not an image."; $uploadOk = 0; } } else { echo"did not change"; } 还是Ssrializable,它都适用。