序列化和反序列化
为什么要序列化
凡是离开内存的信息都要进行序列化
序列化最终的目的是为了对象可以存储,和网络传输。进行存储和网络传输的方式就是IO,而IO支持的数据格式就是字节数组
只把对象转成(0和1的)字节数组还不行,因为没有规则的字节数组我们是没办法把对象的本来面目还原回来的(即拿到一堆01但是并不知道这些01代表的含义),所以我们必须在把对象转成字节数组的时候就制定一种规则(序列化),那么我们从IO流里面读出数据的时候再以这种规则把对象还原回来(反序列化)
这就好比我们要把一栋房子从一个地方运输到另一个地方去,序列化就是我把房子拆成一个个的砖块放到车子里,然后留下一张房子原来结构的图纸,反序列化就是我们把房子运输到了目的地以后,根据图纸把一块块砖头还原成房子原来面目的过程
对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术
序列化的方式
序列化只是一种拆装组装对象的规则,那么这种规则肯定也可能有多种多样,比如现在常见的序列化方式有:
JDK(不支持跨语言)、JSON、XML、Hessian/Hessian2、Kryo(不支持跨语言)、Thrift、Protobuf、FST(不支持跨语言)
JAVA序列化中常见的问题
-
问题一:static 属性不能被序列化
原因:序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量。
-
问题二:Transient 属性不会被序列化
transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
序列化通常会用于网络传输数据对象,而对象中常常会含有敏感数据,所以黑客常常会攻击这点,攻击手段通常是利用反序列化过程构造恶意代码,怎么应对这种情况呢?可以使用transient关键字来修饰这个属性,这样在反序列化之后该属性就会为空,如果一定要传递的话,可以使用对称加密或非对称加密独立传输
-
父类、子类序列化问题
序列化是以正向递归的形式进行的,如果父类实现了序列化那么其子类都将被序列化;子类实现了序列化而父类没实现序列化,那么只有子类的属性会进行序列化,而父类的属性是不会进行序列化的。
序列化注意事项
- 序列化对象必须实现序列化接口。
- 序列化对象里面的属性是对象的话也要实现序列化接口。
- 类的对象序列化后,类的序列化ID不能轻易修改,不然反序列化会失败。
- 类的对象序列化后,类的属性有增加或者删除不会影响序列化,只是值会丢失。
- 如果父类序列化了,子类会继承父类的序列化,子类无需添加序列化接口。
- 如果父类没有序列化,子类序列化了,子类中的属性能正常序列化,但父类的属性会丢失,不能序列化。
- 用Java序列化的二进制字节数据只能由Java反序列化,不能被其他语言反序列化。如果要进行前后端或者不同语言之间的交互一般需要将对象转变成Json/Xml通用格式的数据,再恢复原来的对象。
字节码(class文件)和序列化串
-
字节码(class)为了指导虚拟机的运行
-
序列化串为了暂存活化的内存对象到IO中去 https://www.zhihu.com/question/40547395/answer/87378680
-
二者都是具有一定组装规则的二机制流