JAVA 序列化,反序列化

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

序列化,反序列化

一、什么是序列化?

把 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 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3200 引用 • 8216 回帖

相关帖子

欢迎来到这里!

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

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