java中什么是序列化和反序列化?

java中什么是序列化和反序列化?

谢邀

这篇回答我们详细介绍下Java中的序列化和反序列化。

首先我们介绍下序列化和反序列化的概念:

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

在Java中,如果一个对象要想实现序列化,必须要实现下面两个接口之一:

那这两个接口是如何工作的呢?两者又有什么关系呢?我们分别进行介绍。

2.1 Serializable 接口

一个对象想要被序列化,那么它的类就要实现此接口或者它的子接口。

这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。不想序列化的字段可以使用transient修饰。

由于Serializable对象完全以它存储的二进制位为基础来构造,因此并不会调用任何构造函数,因此Serializable类无需默认构造函数,但是当Serializable类的父类没有实现Serializable接口时,反序列化过程会调用父类的默认构造函数,因此该父类必需有默认构造函数,否则会抛异常。

使用transient关键字阻止序列化虽然简单方便,但被它修饰的属性被完全隔离在序列化机制之外,导致了在反序列化时无法获取该属性的值,而通过在需要序列化的对象的Java类里加入writeObject()方法与readObject()方法可以控制如何序列化各属性,甚至完全不序列化某些属性或者加密序列化某些属性。

2.2 Externalizable 接口

它是Serializable接口的子类,用户要实现的writeExternal()和readExternal() 方法,用来决定如何序列化和反序列化。

因为序列化和反序列化方法需要自己实现,因此可以指定序列化哪些属性,而transient在这里无效。

对Externalizable对象反序列化时,会先调用类的无参构造方法,这是有别于默认反序列方式的。如果把类的不带参数的构造方法删除,或者把该构造方法的访问权限设置为private、默认或protected级别,会抛出java.io.InvalidException: no valid constructor异常,因此Externalizable对象必须有默认构造函数,而且必需是public的。

2.3 对比

使用时,你只想隐藏一个属性,比如用户对象user的密码pwd,如果使用Externalizable,并除了pwd之外的每个属性都写在writeExternal()方法里,这样显得麻烦,可以使用Serializable接口,并在要隐藏的属性pwd前面加上transient就可以实现了。如果要定义很多的特殊处理,就可以使用Externalizable。

当然这里我们有一些疑惑,Serializable 中的writeObject()方法与readObject()方法科可以实现自定义序列化,而Externalizable 中的writeExternal()和readExternal() 方法也可以,他们有什么异同呢?

在序列化过程中,可以控制序列化的版本。该字段为被序列化对象中的serialVersionUID字段。

一个对象数据,在反序列化过程中,如果序列化串中的serialVersionUID与当前对象值不同,则反序列化失败,否则成功。

如果serialVersionUID没有显式生成,系统就会自动生成一个。生成的输入有:类名、类及其属性修饰符、接口及接口顺序、属性、静态初始化、构造器。任何一项的改变都会导致serialVersionUID变化。

属性的变化都会导致自动生成的serialVersionUID发生变化。例如,对于对象A,我们生成序列化的S(A),然后修改A的属性,则此时A的serialVersionUID发生变化。反序列化时,S(A)与A的serialVersionUID不同,无法反序列化。会报序列号版本不一致的错误。

为了避免这种问题, 一般系统都会要求实现serialiable接口的类显式的生明一个serialVersionUID。显式定义serialVersionUID的两种用途:

如果我们保持了serialVersionUID的一致,则在反序列化时,对于新增的字段会填入默认值null(int的默认值0),对于减少的字段则直接忽略。

我们假设有一个对象需要进行序列化:

然后,可以通过以下方式进行序列化和反序列化:

这样,我们将对象user的信息序列化后写入到二进制文件中,并读出来之后又反序列化为newUser对象。

关于序列化的使用,推荐大家阅读MyBatis的源码。为什么呢?因为MyBaits作为一个ORM框架,需要频繁进行内存中对象和数据库中序列化字符串的转换。在这方面,用的很到位。

这方面,推荐一本书《通用源码阅读指导书》。这是一本以MyBatis的源码为实例讲述源码阅读方法的书籍,非常推荐。

在书中:

非常棒!

多读读源码,进步会很大。这本书非常适合大家上手读源码。

点个赞再走!不点赞不让走!

可以关注我,偶尔出没解答 软件架构和编程 相关问题。