技术开发 频道

关于 Java 对象序列化您不知道的5件事

  到现在为止,还没有看到什么新鲜的或令人兴奋的事情,但是这是一个很好的出发点。我们将使用 Person 来发现您可能不 知道的关于 Java 对象序列化 的 5 件事。

  1. 序列化允许重构

  序列化允许一定数量的类变种,甚至重构之后也是如此,ObjectInputStream 仍可以很好地将其读出来。Java Object Serialization 规范可以自动管理的关键任务是:

  1.将新字段添加到类中

  2.将字段从 static 改为非 static

  3.将字段从 transient 改为非 transient

  取决于所需的向后兼容程度,转换字段形式(从非 static 转换为 static 或从非 transient 转换为 transient)或者删除字段需要额外的消息传递。

  重构序列化类

  既然已经知道序列化允许重构,我们来看看当把新字段添加到 Person 类中时,会发生什么事情。

  如清单 3 所示,PersonV2 在原先 Person 类的基础上引入一个表示性别的新字段。

  清单 3. 将新字段添加到序列化的 Person 中

enum Gender
{
    MALE, FEMALE
}

public class Person
    
implements java.io.Serializable
{
    
public Person(String fn, String ln, int a, Gender g)
    {
        
this.firstName = fn; this.lastName = ln; this.age = a; this.gender = g;
    }
  
    
public String getFirstName() { return firstName; }
    
public String getLastName() { return lastName; }
    
public Gender getGender() { return gender; }
    
public int getAge() { return age; }
    
public Person getSpouse() { return spouse; }

    
public void setFirstName(String value) { firstName = value; }
    
public void setLastName(String value) { lastName = value; }
    
public void setGender(Gender value) { gender = value; }
    
public void setAge(int value) { age = value; }
    
public void setSpouse(Person value) { spouse = value; }

    
public String toString()
    {
        
return "[Person: firstName=" + firstName +
            
" lastName=" + lastName +
            
" gender=" + gender +
            
" age=" + age +
            
" spouse=" + spouse.getFirstName() +
            
"]";
    }    

    
private String firstName;
    
private String lastName;
    
private int age;
    
private Person spouse;
    
private Gender gender;
}

  序列化使用一个 hash,该 hash 是根据给定源文件中几乎所有东西 — 方法名称、字段名称、字段类型、访问修改方法等 — 计算出来的,序列化将该 hash 值与序列化流中的 hash 值相比较。

  为了使 Java 运行时相信两种类型实际上是一样的,第二版和随后版本的 Person 必须与第一版有相同的序列化版本 hash(存储为 private static final serialVersionUID 字段)。因此,我们需要 serialVersionUID 字段,它是通过对原始(或 V1)版本的 Person 类运行 JDK serialver 命令计算出的。

  一旦有了 Person 的 serialVersionUID,不仅可以从原始对象 Person 的序列化数据创建 PersonV2 对象(当出现新字段时,新字段被设为缺省值,最常见的是“null”),还可以反过来做:即从 PersonV2 的数据通过反序列化得到 Person,这毫不奇怪。

0
相关文章