JAVA 序列化,反序列化

本贴最后更新于 2584 天前,其中的信息可能已经事过境迁

序列化,反序列化

一、什么是序列化?

把 JAVA 对象 转换成可保存可传输的形式的过程就是序列化。

二、什么是反序列化?

把一个对象序列化的结果恢复成原对象的过程就是反序列化。

序列化,反序列化的实现

一、Java 中如何实现序列化
一个类只需要实现 Serializable 接口就可以使其实例对象可序列化和反序列化。示例如下:

//这是一个Person类
import  java.io.Serializable;
/**
 * Created with IntelliJ IDEA. 
 * Author:rzx * Date:2017/10/24 
 */
public class Person implements Serializable {
    private String name;
    private Integer age;
    private String desc;

    public Person(String name, Integer age,String desc) {
        this.name = name;
        this.age = age;
        this.desc = desc;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
  public String toString() {
        return this.getClass().getSimpleName()+"["+this.getName()+","+this.getAge()+","+this.desc+"]";
    }
}

下面我们来手动序列化/反序列化一个 Person 的实例

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * Created with IntelliJ IDEA. 
 * Author:rzx * Date:2017/10/24 
 */
public class SerialiableTest {
  public static void main(String[] args) throws Exception{
  //实例化一个对像
  Person person = new Person("Aami",18,"this is a Person Object");
  //看看对象内容
  System.out.println(person.toString());// Person[Aami,18,this is a Person Object]

  //序列化:的大了一个二进制文件,这样我们就可以在网络中传输了这个对象了
  ObjectOutputStream osu = new ObjectOutputStream(new FileOutputStream("Person.sl"));
  osu.writeObject(person);

  //反序列化:得到一个序列化的文件,我们把他恢复成一个对象
  ObjectInputStream osi = new ObjectInputStream(new FileInputStream("Person.sl"));
  Object obj = osi.readObject();

  //我们将一个对象反序列化了,来看看它是谁
  System.out.println(obj);
  //结果是:Person[Aami,18,this is a Person Object]原来是一个Person对象。
  //尽管我们用一个Object接受它,但它很清楚自己是一个Person
  }
}

运行结果:

Person[Aami,18,this is a Person Object]
Person[Aami,18,this is a Person Object]

二、自动序列化是如何完成的
实例中显示调用 ObjectInputStream/ObjectOutputStream,来进行序列化和反序列化,在很多时候我们并没有(或者并不需要写)写这些代码,当我们实现了 Serializable 接口的时候就声明这是个可序列化的类,当需要序列化的时候(如:网络传输。。。)系统会自动将其序列化进行序列化、反序列化时,虚拟机会首先试图调用对象里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化。如果没有这样的方法,那么默认调用的是 ObjectOutputStream的defaultWriteObject以及ObjectInputStream的defaultReadObject方法。换言之,利用自定义的 writeObject 方法和 readObject 方法,用户可以自己控制序列化和反序列化的过程。

transient 关键字

Transient 关键字:用于标识此属性无需序列化,那么在序列化的时候就不会对此属性进行序列化。示例如下:

//将Person中的desc属性加上transient修饰,其他代码不变:
 private transient String desc;

再次运行结果:

Person[Aami,18,this is a Person Object]
Person[Aami,18,null]

我们发现反序列化之后的 desc 属性变成了 null,说明此属性并未序列化。

serialVersionUID:序列化版本号

我们将上一步的代码再做一点修改:Person 类加上一个属性 sex,此时 Person,有了四个属性。

private String sex;

我们 再运行SerialiableTest类的反序列化部分 即只运行如下部分:

//反序列化:得到一个序列化的文件,我们把他恢复成一个对象
ObjectInputStream osi = new ObjectInputStream(new FileInputStream("Person.sl"));
Object obj = osi.readObject();

//我们将一个对象反序列化了,来看看它是谁
System.out.println(obj);

这一步是什么意思呢?就是说我们把一个对象进行了序列化,得到一个文件 Person.s1,然后呢修改了这个 Person 类,然后呢我们去反序列化这个文件。得到结果如下:

Exception in thread "main" 
java.io.InvalidClassException: com.rzx.train.serialiableT.Person; 
local class incompatible: 
  stream classdesc serialVersionUID = 5957172176274511819,
  local class serialVersionUID = 3320482973311753842
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
	at com.rzx.train.serialiableT.SerialiableTest.main(SerialiableTest.java:26)

爆出了一个异常:本地类不匹配,并且 stream classdesc serialVersionUID = 5957172176274511819,而 local class serialVersionUID = 3320482973311753842,好像是说序列化的类的 serialVersionUID 和当前的类的 serialVersionUID 不一致导致他不知道要把自己反序列化程哪一个类了。。他找不到创造自己的类了。

**如何保证序列化后一定能够反序列化呢? **
我们手动给这个类指定一个 serialVersionUID 就可以了,尽管类的内容修改了,但是这个 serialVersionUID 没变,反序列化依然能找到这个类。

private static final long serialVersionUID = 1361127491317406689L;

**指定 serialVersionUID 方式: **
1、默认是:1L
2、根据类名、接口名、成员方法以及属性等来生成一个 64 位的 Hash 字段

在 IDE 中会自动提示我们添加一个 serialVersionUID。

...待续

  • 序列化
    6 引用 • 18 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
rzx
此生最怕深情被辜负,最怕兄弟成陌路。对世界充满善意,同时又充满深深的恨意,我渴望天降甘霖福泽众生,又渴望灭世洪水重创世纪。 广州