1.java序列化需要实现Serializaible接口或者Externalizable接口

2.java实现序列化的作用:

        1.方便在远程调用时对象的解码与编码,就像new对象之间直接调用,不需要像传输对象之间像JSON转换一样转来转去

        2.序列化的能力:为了在程序中能直接以对象的形式进行保存,直接进行调用

        序列化的方式:按照一定的格式将java对象的状态转成可接受的形式,以便于存储和运输

按照一定的格式将java对象的状态转成可接受的形式(对象持久到介质中,像实现对象直接存储)

        3.对象可以自定义存储格式        (没例子)

例子:

常见的使用方式是直接将对象写入流中,比如下面的例子中,创建了FileOutputStream对象,对应输出到tmp.o文件中。然后创建
ObjectOutputStream对象嵌套前面的输出流,当我们调用writeObject方法时即能进行序列化操作。(本质直接存储到磁盘吧)

writeObject方法需要特别说明一下,当我们对某个对象进行写入时,其实不仅仅序列化该对象,它还会去遍历寻找相关引用的其它对象,由自己和其它引用对象组成的一个完整的对象图关系都会被序列化。除了一些特殊指定的类,普通类必须实现Serializable或Externalizable接口才能被序列化。

问题:
平常实体类没有实现Serializable接口,怎么也能存进数据库呢?
是因为在声明变量的时候,例如String、int、Boolean等时,数据类型已经实现了序列化
注意:父类的序列化

如果一个子类实现了Serializable接口而父类没有实现该接口,则在序列化子类时,子类的属性状态会被写入而父类的属性状态将不被写入。所以如果想要父类属性状态也一起参与序列化,就要让它也实现Serializable接口。

哪些字段会被序列化:

3.反序列化:

        1.即通过字节流还原对象

        例子:
反序列化是序列化的反向操作,即通过字节流来还原Java对象。看下面的例子,首先创建FileInputStream对象,其对应的文件为tmp.o。然后创建ObjectInputStream对象嵌套前面的输入流,接着则可以调用readObject方法读取对象。readObject方法除了会恢复对象自己之外,它还会遍历整个完整的对象图关系,创建整个对象图包含的所有对象。

另外,如果父类未实现Serializable接口则反序列化生成的对象会再次调用父类的构造函数,以此完成对父类的初始化。所以父类属性初始值一般都是类型的默认值。比如下面的代码,Father类的属性不会参与序列化,反序列化时Father对象的属性的值为默认值0。

 

在序列化时对象的哪些字段会参与到序列化中呢?其实有两种方式决定哪些字段会被序列化。一是默认方式,Java对象中的非静态和非transient的字段都会被定义为需要序列化的字段。另外一种方式是通过ObjectStreamField数组来声明需要序列化的对象。

可以看到对象中普通的属性都是默认会被序列化的,而如果某些包含了敏感信息的属性我们不希望它参与序列化,那么最简单的方式就是可以将该字段声明为transient。

如何使用ObjectStreamField呢?举个例子,
如下代码中A类中有name和password两个字段,我们通过ObjectStreamField数组声明只需序列化name字段
。我们不必纠结为什么这样声明,这仅仅是一个约定而已。

Externalizable接口

Externalizable接口主要就是提供给用户自己控制序列化内容,虽然前面我们也看到了transient和ObjectStreamField都能定义参与序列化的字段,但实际上Externalizable接口提供了更加灵活的方式。可以看到它其实继承了Serializable接口,
然后提供了writeExternal和readExternal两个方法,我们就是在这两个方法内控制序列化和反序列化。

 比如下面的例子,我们可以在writeExternal方法中额外写入Date对象,然后再写入value值。对应地,反序列化时则是
在readExternal方法中读取Date对象和value。这样就完成了自定义序列化操作。

 写入时代替:

正常情况下序列化某个对象时写入的正是当前的对象,但如果说我们要替换当前的对象而写入其他对象的话则可以通过writeReplace方法来实现。比如下面,person类通过writeReplace方法最终可以写入Object数组对象。所以我们在反序列化时就不再是转换成Person类型,而是要转换为Object数组对象。

 读取时代替:

上面介绍了在写入时可以替换对象,而在读取时也同样支持替换对象的,它是通过readResolve方法实现的
。比如下面的代码,在readResolve方法返回2222,则反序列化读取时不再是Person对象,而是2222。

AQS序列化 :

JDK内置并发AQS同步器实现了Serializable接口,其中head和tail变量声明为transient。也就是说
如果对AQS同步器对象进行序列化的话,队列是不参与序列化的,只有同步状态会参与序列化。也就是说序列化会让AQS丢失队列信息,只能保留同步状态信息。

 

技术
下载桌面版
GitHub
百度网盘(提取码:draw)
Gitee
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:766591547
关注微信