suninf 's blog

Enjoy From Programming And Technique

Java序列化

Catalog

Java对象的序列化主要有两种用途:

  1. 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2. 在网络上传送对象的字节序列。

序列化接口与API

在Java中,只要一个类实现了java.io.Serializable接口(没有方法),那么它就可以被序列化。

对象序列化步骤:

  1. 创建一个对象输出流ObjectOutputStream,它可以包装一个其他类型的目标输出流,如文件输出流;
  2. 通过对象输出流的writeObject(obj)方法写对象。

对象反序列化步骤:

  1. 创建一个对象输入流ObjectInputStream,它可以包装一个其他类型的源输入流,如文件输入流;
  2. 通过对象输入流的readObject()方法读取对象。

父类对象序列化

要想将父类对象也序列化,就需要让父类也实现Serializable 接口

transient控制符

transient控制符表示该属性不参与序列化

关于静态变量

静态变量不会被序列化,因为所有的对象共享同一份静态变量的值

例子

import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = -5809782578272943989L;
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

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

    public void setName(String name) {
        this.name = name;
    }
}
// Test
public class MainTest {

    public static void main(String[] args) {

        byte[] buf = SerializePerson();
        Person p = DeserializePerson(buf);

        System.out.println(MessageFormat.format("name={0}, age={1}",
            p.getName(), p.getAge()));
    }

    private static byte[] SerializePerson() {
        Person person = new Person();
        person.setName("suninf");
        person.setAge(25);

        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(os);
            oos.writeObject(person);
            oos.close();

            return os.toByteArray();
        } catch (FileNotFoundException ex) {
        } catch (IOException ex) {
        }

        return null;
    }

    private static Person DeserializePerson(byte[] buf) {
        Person person = null;
        try {
            InputStream is = new ByteArrayInputStream(buf);
            ObjectInputStream ois = new ObjectInputStream(is);
            person = (Person) ois.readObject();
        } catch (FileNotFoundException ex) {
        } catch (IOException ex) {
        } catch (ClassNotFoundException ex) {
        }

        return person;
    }
}

serialVersionUID的作用

s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D​ 字​面​意​思​上​是​序​列​化​的​版​本​号​,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量,版本不一致会抛出异常。

只要指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用。

自定义序列化行为

序列化类中包含writeObject 和 readObject 方法

要序列化的类,可以通过实现writeObject 和 readObject来自定义序列化的实现,在使用ObjectOutputStream的writeObject方法和ObjectInputStream的readObject方法时,会通过反射的方式调用。

比如,ArrayList<T>就自定义实现了writeObject 和 readObject 方法。

Externalizable接口

  • Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为
  • 而仅实现Serializable接口的类可以采用默认的序列化方式

参考

Comments