java序列化 java为什么使用序列化

编辑:
发布时间: 2020-12-24 03:12:16
分享:

参考地址:https://blog.csdn.net/postersxu/article/details/78492523

1.什么是序列化?

从字面上理解就是有序,标准而整齐。想象我们中学时代的早操与大学入学时的军训的场景,我们排好队,迈着整齐的步伐进入操场做操、训练,结束后又迈着同样的步调返回教室或食堂。从进入操场到从操场出来,我们没有变,每个人还是在自己的位置上。这就是一个类似于序列化的场景,可能不太贴切...

标准的定义是这样描述的:序列化是一种处理对象流的机制,而所谓对象流就是将对象的具体内容流化。这么做的目的是方便进行读写操作和异域传输。

2.如何实现序列化?

实现序列化的方式很简单,就是简单的实现序列化接口,即implementsSerializable。在实现序列化接口后,java编译会提示生成一个序列化ID,可以默认生成,也可以自定义。这里的自定义并不是自己随便定义一个数字,而是根据当前类的一些特点如类名,成员变量等由系统来生成一个64位的哈希字段。事实上,尽管需要定义一个序列化ID,但是我们实现序列化接口总体上还是非常轻松简单的,无需去实现它的方法,因为它本身就是一个标志而已。这个标记存在的意义就是告诉别人当前实体类已经实现了序列化,也可以被序列化。在这一点上,和定义后台校验的分组十分相似,我们需要的仅仅是这个标志。

以下为两种序列化ID的截图:

那么这两种序列化ID有什么区别呢?

在说明两者间的不同前,先解释一下序列化的应用场景:

3.序列化的应用场景

在上文中已经解释了什么是序列化。那序列化可以做到什么呢?我认为主要有两方面,这两点正好对应两个应用场景。

一是实现pojo对象的读写操作,将每个对象转换为字节流,而这些字节流可以被持久化到设备上,再次读取时会将字节流还原成对象。相当于将大象切割成几份放到冰箱里,当拿出来时,还是一头活生生的大象。这里还原对象使用的是反序列化。当我们希望某些数据能在程序停止运行后,还能继续存在。在程序再次执行时还能获取这些数据时,或者让其他的程序也能够利用这些数据资源时。这就是我理解的应用场景一。

二是实现网络间的数据传输。网络间的数据传输是高频发而且数据量也是非常大的。以订单数据传输为例,当我们希望获取到订单类里的全部数据并据此生成一份订单的excel文件时,这个订单类就必须要实现序列化,这是我理解的应用场景二。

4.序列化ID作用

序列化ID的每次生成不一定是相同的,当我们在修改实体类的变量或方法名等,会导致序列化ID出现变化。这个ID类似于version-版本号。我们知道,hibernate里有乐观锁这个机制,它就是通过添加一个版本号,每次在修改数据时,通过比对版本号是否一致来避免数据修改出现错误。而序列化也是如此。

当我们将某个实体类对象持久化到本地设备后,可能过段时间,我们想要去修改类里面的某个变量或者说添加新的变量。如果说我们定义了序列化ID,那这时我们可以通过反序列化获取实体类的数据,然后再去添加或者修改某项数据。如果没有定义序列化ID,同样的我们去进行本地数据的反序列化,这时会因为序列化ID不一致而导致操作失败。

以下为操作的实例:

首先定义一个学生实体类Studengt,类中规定了学生的姓名和年龄。

接下来写一个序列化保存数据的方法,将数据持久化到本地。

使用main方法调用后,可以看见控制台打印如下内容:

接下来我们修改学生的实体类,例如添加联系电话变量,再使用反序列化来获取数据:

main方法调用反序列化:

可以看到,因为修改后的学生实体类的序列化ID已经与之前的序列化ID不一致,导致反序列化失败:

那么,我们在实体类中直接定义好序列化ID,执行结果又是如何呢?

执行同样的方法,再添加联系电话变量,执行反序列化方法,最后的结果如下:

可能大家已经明白了序列化ID的作用,但是对于默认的序列化ID 1L与根据当前类特点生成的序列化ID的区别有所疑问。两者的区别如下:

某些情况下,这个学生类可能用于统计学生的年龄分布,但是过了一段时间,又希望能通过这个学生类来获取学生的性别分布与成绩间的关系。这时候就需要一个不同的序

列化ID来作为版本号,默认的1L已经不能满足这个需求。当然,我们可以手动的将1L改为2L来区别~

相关阅读
热门精选
孩子 皮肤