我的个人网站 www.ryzeyang.top

内容概览
通过详细的流程图带你一步步看看序列化的核心过程做了什么?一起来探究这序列化的过程吧!

让我们来看下今天的主角 objectOutputStream.writeObject(s2);
没错,就是java ObjectOutputStream中的一个主要方法 writeObject,通过该方法,我们可以将对象序列化????。
问题:序列化到底序列化了什么?

流程图

writeObject序列化过程之Serializable方式源码详解(流程图)

Answer

通过writeObject源码的注释可知,序列化时会将指定的对象写入ObjectOutputStream,具体包括以下几个

  1. 对象的字节码
  2. 类名
  3. 非transient或者非static的fields(字段)
  4. 父类

源码解读

writeObject

writeObject序列化过程之Serializable方式源码详解(流程图)
接着我们来看看writeObject0这个底层方法的实现。????

ObjectStreamClass

它是序列化操作的核心对象!desc贯穿整个序列化过程。
writeObject序列化过程之Serializable方式源码详解(流程图)

那它是个怎样的类呢?????
writeObject序列化过程之Serializable方式源码详解(流程图)
这个注释的大概意思是 它是 类的序列化描述符,包含了类的名字和序列化版本号serialVersionUID,还有这个类的加载是在lookup方法中的(重点!!)。

lookup(重点)

writeObject0中有下面这段代码,就是它创建了我们的主角ObjectStreamClass的,让我们一起看下吧!
writeObject序列化过程之Serializable方式源码详解(流程图)
进入到该方法中可以看到如下的注释:

Looks up and returns class descriptor for given class, or null if class is non-serializable and “all” is set to false.

简单说就是会去创建这个ObjectStreamClass????
在方法中可以看到如下代码
writeObject序列化过程之Serializable方式源码详解(流程图)
接着进入到它的构造器中:
writeObject序列化过程之Serializable方式源码详解(流程图)
我们这个类是serializable的,会走下面这段逻辑
writeObject序列化过程之Serializable方式源码详解(流程图)

getDeclaredSUID !

可以看到该方法会返回这个版本号serialVersionUID,没有的话返回null。????
writeObject序列化过程之Serializable方式源码详解(流程图)

getSerialFields !

该方法的作用是:返回可以序列化的字段数组????
writeObject序列化过程之Serializable方式源码详解(流程图)
先看第一个红框的内容getDeclaredSerialFields

getDeclaredSerialFields !!

该方法会去获取你指定的可序列化字段 同时该字段 serialPersistentFields在序列化类中必须是由private static final修饰的????
有指定的话就不会走上图第二个红框中的方法getDefaultSerialFields

writeObject序列化过程之Serializable方式源码详解(流程图)

getDefaultSerialFields !!

这里static是8,transient是16

十进制 二进制
8 0000 1000
16 0001 0000

进行或运算int mask = Modifier.STATIC | Modifier.TRANSIENT;的值用二进制表示为 0001 1000
writeObject序列化过程之Serializable方式源码详解(流程图)
这时你可能会想到那个版本号也是static修饰的 ,但是我们前面已经用这个
getDeclaredSUID方法去获取它了,所以序列化时 应该序列化了所有非static,非transient的字段还有特殊字段,版本号serialVersionUID

writeOrdinaryObject

在了解了ObjectStreamClass类后,我们继续往下查找,找到writeOrdinaryObject`方法 ????
writeObject序列化过程之Serializable方式源码详解(流程图)
进入该方法,从代码上的注释可以知道,该方法会将“普通”可序列化对象的表示形式写入流。(即不是字符串、类、ObjectStreamClass、数组或枚举常量)
writeObject序列化过程之Serializable方式源码详解(流程图)

writeClassDesc !

该方法会将ObjectStreamClass写到流中。????
writeObject序列化过程之Serializable方式源码详解(流程图)
接着我们看看这个writeNonProxyDesc方法
writeObject序列化过程之Serializable方式源码详解(流程图)
进入到上图红框中的方法writeClassDescriptor
writeObject序列化过程之Serializable方式源码详解(流程图)

writeNonProxy !

终于来到最核心的地方啦!,通过下面两个方法,out会将类名和它的版本号
serialVersionUID写入到流中
writeObject序列化过程之Serializable方式源码详解(流程图)

接着来到下面这里,会去写入可序列化字段ObjectStreamField的类型和字段名称(注意!这里还没有写入字段的value!写值的操作在方法writeSerialData)。
writeObject序列化过程之Serializable方式源码详解(流程图)

writeSerialData

接着进入到writeSerialData方法,该方法的目的是:为给定对象的每个可序列化类写入实例数据,从父类到子类????
writeObject序列化过程之Serializable方式源码详解(流程图)

defaultWriteFields

接着进入到defaultWriteFields方法,该方法的目的是:获取给定对象的可序列化字段的值并将其写入流,desc会指定哪些field要写,按什么顺序写。????
writeObject序列化过程之Serializable方式源码详解(流程图)
让我们看看该方法中的具体实现。如图所示,如果还有非基本数据类型的字段话,会再去遍历,然后又去执行writeObject0(又回到最开始啦!)????
writeObject序列化过程之Serializable方式源码详解(流程图)

总结

对实现了可序列化接口Serializable的类,在序列化时,会先去创建ObjectStreamClass对象,该对象封装了序列化类的版本号serialVersionUID,类的全称,可序列化字段等,如果你指定了序列化的字段serialPersistentFields,则不会去获取默认的可序列化字段,反之获取默认的(即非static,非transient的)。最后通过writeNonProxy方法将类名,版本号,还有可序列化字段的类型,名称到流中,接着通过writeSerialData对这些可序列化字段进行赋值。

有什么不对的请多多指教!欢迎留言讨论????

相关文章:

  • 2022-12-23
  • 2021-08-31
  • 2022-12-23
  • 2022-12-23
  • 2021-07-07
  • 2021-11-14
  • 2021-10-31
猜你喜欢
  • 2021-04-25
  • 2022-12-23
  • 2021-05-30
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案