47、序列化和反序列化

在工作中有可能遇到多台机器远程通信的情况,如果要将机器A中的某个java对象传输到机器B上面,需要将这个java对象转换为字节序列然后进行传输。将对象转换为字节序列的过程叫做序列化,反之叫做反序列化。

一个对象如果支持序列化,需要实现Serializable的接口,这个接口中没有任何方法,实现该接口后,JVM会给这个对象做特殊待遇

将java对象保存到硬盘里面

使用序列化还可以将一个对象保存到硬盘中,然后再通过反序列化将该对象读取到内存里面。

创建一个Student类,实现Serializable接口

package com.monkey1024.serializable;

import java.io.Serializable;

public class Student implements Serializable {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

使用ObjectOutputStream将Student对象写出到硬盘中

package com.monkey1024.serializable;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 * 将Student对象序列化到硬盘中
 *
 */
public class ObjectOutput {

    public static void main(String[] args) {
        Student s = new Student();
        s.setName("张三");

        // 创建输出流(序列化流) 
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("zhangsan"));) {
            //将对象写出到硬盘中
            oos.writeObject(s);
            oos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用ObjectInputStream将硬盘中的对象读取到内存中

package com.monkey1024.serializable;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * 从硬盘中读取Student对象
 *
 */
public class ObjectInput {

    public static void main(String[] args) {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("zhangsan"));) {
            Student s = (Student)ois.readObject();
            System.out.println(s.getName());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

序列化版本号

在一个类实现Serializable接口后,系统会给每个对象一个序列化版本号,当这个类的源码被修改后,系统会重新分配一个新的序列化版本号,这样做的好处就是保证序列化和反序列化的对象内容一致。例如将一个对象序列化到硬盘之后,修改这个对象所对应类的源码,在进行反序列化是就会报出InvalidClassException异常。如果手动编写序列化版本号之后,就不会出现这个异常了。

package com.monkey1024.serializable;

import java.io.Serializable;

public class Student implements Serializable {

    /**
     * 自动生成序列化版本号
     */
    private static final long serialVersionUID = -716323668524282676L;

    private String name;
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

transient关键字

如果不希望将Student类中的age属性序列化,可以使用transient声明该属性,在序列化时将忽略这个属性。

package com.monkey1024.serializable;

import java.io.Serializable;

public class Student implements Serializable {

    /**
     * 自动生成序列化版本号
     */
    private static final long serialVersionUID = -716323668524282676L;

    private String name;

    //age不序列化
    transient private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
原文地址:https://www.cnblogs.com/zhuifeng-mayi/p/10145545.html