对象的序列化和反序列化---使用Serializable接口

来源:互联网 发布:mysql having 用法 编辑:程序博客网 时间:2024/06/05 03:26

什么是对象的序列化和反序列化?
对象序列化,就是将Object对象转换成byte字节序列;这里使用ObjectOutputStream — writeObject();
对象的反序列化,就是将byte字节序列转换成Object对象;这里使用ObjectInputStream—readObject();
Serializable接口
是java所提供的一个序列化方式,为对象提供标准的序列化和反序列化操作;
对象序列化需要实现Serializable接口,只是一个规定,标准,这个接口里面没有任何方法;
想让一对象实现序列化只要这个类实现Serializable接口并声明一个serialVersionUID,比如下面

public class Student implements Serializable {    private static final long serialVersionUID = 8809363383079722734L;    private int age;    private String name;    private String address;    public Student() {        super();    }    public Student(int age, String name, String address) {        super();        this.age = age;        this.name = name;        this.address = address;    }    @Override    public String toString() {        return "Student [age=" + age + ", name=" + name + ", address="                + address + "]";    }}

实际上这个serialVersionUID也不是必须的。我们不声明这个serialVersionUID同样也可以实现序列化。但这将会对反序列化过程产生影响。
这个serialVersionUID是用来辅助序列化和反序列化的,原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常的被反序列化。
serialVersionUID的详细工作机制是这样的:
1.序列化的时候系统会把当前类的serialVersionUID写入序列化的文件中(也可能是其他的中介),
2.当反序列化的时候系统会去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,
3.如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以反序列化;
如果不一致说明当前类和序列化的类相比发生了某些变化,比如成员变量数量、类型可能发生了变化,这时候无法正常反序列化。看下面示例演示序列化和反序列化

public class Main {    public static void main(String[] args) {        try {            // 序列化            serialObject();            // 反序列化             reSerialObject();        } catch (Exception e) {            e.printStackTrace();        }    }    // 序列化过程    private static void serialObject() throws IOException,            FileNotFoundException {        Student stu = new Student(10, "liming", "杨集");        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(                "student.txt"));        oos.writeObject(stu);        oos.close();    }    // 反序列化过程    private static void reSerialObject() throws IOException,            FileNotFoundException, ClassNotFoundException {        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(                "student.txt"));        Student student = (Student) ois.readObject();        ois.close();        System.out.println(student.toString());    }}

上面如果正常的话,是可以完整进行序列化和反序列化工作的,现在如果我们注释反序列化方法reSerialObject(),运行代码先执行序列化,然后在改动如下信息:
1,将Student类中的private static final long serialVersionUID = 1L;
2,注释掉序列化的代码,去掉反序列化的注释。在运行一下:
这时反序列化就会出问题了,报如下错误:

Exception in thread "main" java.io.InvalidClassException: com.io.test.Student; local class incompatible: stream classdesc serialVersionUID = 8809363383079722734, local class serialVersionUID = 1    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.readOrdinaryObject(Unknown Source)    at java.io.ObjectInputStream.readObject0(Unknown Source)    at java.io.ObjectInputStream.readObject(Unknown Source)    at com.io.test.Main.main(Main.java:28)

这个手序列化就会失败了!
transient关键字可以使得某个字段不被序列化;

private transient String address;//系统默认不会被jVM序列化

其实系统默认序列化的方式可以可以通过重写readObject()和writeObject方法来改变,比如下面的例子

public class Student implements Serializable {    private static final long serialVersionUID = 8809363383079722734L;    private int age;    private String name;    private transient String address;//默认是不能序列化的,但是重写了上面两个方法,所以也可以序列化和反序列化    public Student() {        super();    }    public Student(int age, String name, String address) {        super();        this.age = age;        this.name = name;        this.address = address;    }    @Override    public String toString() {        return "Student [age=" + age + ", name=" + name + ", address="                + address + "]";    }    /**重写系统反序列化的方法*/    private void readObject(java.io.ObjectInputStream s)            throws java.io.IOException, ClassNotFoundException {        s.defaultReadObject();// JVM虚拟机默认的反序列化过程        address = s.readUTF();//反序列化address    }    /**重写系统序列化的方法*/    private void writeObject(java.io.ObjectOutputStream s)            throws java.io.IOException {        s.defaultWriteObject();// JVM虚拟机默认的序列化过程        s.writeUTF(address);//序列化address    }}

到此介绍完毕~~~

0 0