Java对象的序列化与反序列化

来源:互联网 发布:网络教育法学类本科 编辑:程序博客网 时间:2024/05/22 05:17

序列化与反序列化

序列化就是将对象的状态信息转换为可以存的字节序列存等储,在以后将这个字节序列恢复成对象就是反序列化。


实现Serializable的方式

public class Fruit implements Serializable {    /**     *      */    private static final long serialVersionUID = 1L;    private String name;    private int size;    /**     * @param name     * @param size     */    public Fruit(String name, int size) {        super();        this.name = name;        this.size = size;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getSize() {        return size;    }    public void setSize(int size) {        this.size = size;    }    @Override    public String toString() {        return "Fruit [name=" + name + ", size=" + size + "]";    }}
public static void main(String[] args) throws IOException, ClassNotFoundException {        Fruit fruit = new Fruit("banana", 100);        ByteArrayOutputStream out = new ByteArrayOutputStream();        ObjectOutputStream stream = new ObjectOutputStream(out);        stream.writeObject(fruit);        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));        Fruit fruitRecover = (Fruit) in.readObject();        System.out.println(fruitRecover);    }

输出:
Fruit [name=banana, size=100]

上面的例子中可以自定义读和写方法,如果有则调用自己的方法在Fruit中加入

    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {        in.defaultReadObject();        //可以用自己的逻辑读数据        System.out.println("readObject");    }    private void writeObject(ObjectOutputStream out) throws IOException {        out.defaultWriteObject();        //可以用自己的逻辑写数据        System.out.println("writeObject");    }

注意点

  1. 尽量在需要序列化的类中定义序列serialVersionUID ,否则虚拟机将自动调用方法实现一个序列,影响性能。
  2. transient关键字的字段无法实现序列。
  3. 静态成员属于类级别的,所以不能序列化,除非你都在同一个机器(而且是同一个进程),且jvm已经把字段加载进来了。


实现Externalizable的方式

这种方法必须要自己实现读和写,并且必须要有无参数构造器,看下代码

public class Person implements Externalizable {    private String name;    private int age;    public Person() {        super();        System.out.println("default constructor");    }    public Person(String name, int age) {        super();        this.name = name;        this.age = age;        System.out.println("params constructor");    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public void writeExternal(ObjectOutput out) throws IOException {        out.writeObject(name);        out.writeInt(age);        System.out.println("writeExternal");    }    @Override    public void readExternal(ObjectInput in) throws IOException,            ClassNotFoundException {        name = (String) in.readObject();        age = in.readInt();        System.out.println("readExternal");    }}
public static void testES() throws IOException, ClassNotFoundException {        Person person = new Person("zzh", 20);        ByteArrayOutputStream out = new ByteArrayOutputStream();        ObjectOutputStream stream = new ObjectOutputStream(out);        stream.writeObject(person);        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));        Person p = (Person) in.readObject();        System.out.println(p.getAge());    }

输出:
params constructor
writeExternal
default constructor
readExternal
20

一些使用场景

  1. 在一些网络传输、RMI等远程传输。
  2. tomcat在重启时,也会将session中的对象序列化,我们不需要重新登录。
  3. 使用jrdis保存对象时也能用到。


参考

  • 《Java编程思想》
  • http://www.hollischuang.com/archives/1150
0 0