序列化:
将对象变为可传输内容的过程就是序列化.
方式:
1、Java原生:
简介
Java原生序列化实体类必须实现Serializable接口。
原理是通过Java原生流(InputStream和OutputStream)的方式进行转化。
java原生序列化存在的问题
...
1) 序列化数据结果比较大、传输效率比较低;
2) 不能跨语言对接.
以至于在后来的很长一段时间,基于XML格式编码的对象序列化机制成为了主流,一方面解决了多语言兼容问题,
另一方面比二进制的序列化方式更容易理解。
再到后来,基于JSON的简单文本格式编码的HTTP REST接口又基本上取代了复杂的Web Service接口,
成为分布式架构中远程通信的首要选择。但是JSON序列化存储占用的空间大、性能低。
恰当的序列化协议不仅可以提高系统的通用性、强壮型、安全性、优化性能。同时还能让系统更加易于调试和扩展
2、Json序列化
Json序列化一般会使用jackson包,通过ObjectMapper类来进行一些操作,比如将对象转化为byte数组或者将json串转化为对象。
现在的大多数公司都将json作为服务器端返回的数据格式。比如调用一个服务器接口,通常的请求为xxx.json?a=xxx&b=xxx的形式。
3、FastJson序列化
fastjson 是由阿里巴巴开发的一个性能很好的Java 语言实现的 Json解析器和生成器。
特点:速度快,测试表明fastjson具有极快的性能,超越任其他的java json parser。
功能强大,完全支持java bean、集合、Map、日期、Enum,支持范型和自省。无依赖,能够直接运行在Java SE 5.0以上版本, 支持Android。
使用时候需引入FastJson第三方jar包。
4、ProtoBuff序列化
ProtocolBuffer是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化。
适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
优点:跨语言;序列化后数据占用空间比JSON小,JSON有一定的格式,在数据量上还有可以压缩的空间。
缺点:它以二进制的方式存储,无法直接读取编辑,除非你有 .proto 定义,否则无法直接读出 Protobuffer的任何内容。
其与thrift的对比:两者语法类似,都支持版本向后兼容和向前兼容,thrift侧重点是构建跨语言的可伸缩的服务,支持的语言多,同时提供了全套RPC解决方案,
可以很方便的直接构建服务,不需要做太多其他的工作。 Protobuffer主要是一种序列化机制,在数据序列化上进行性能比较,Protobuffer相对较好。
serialVersionUID的作用
* 不实现Serializable接口的类不能被序列化, 会抛出`NotSerializableException`异常
* 实现Serializable接口, 但没有定义serialVersionUID值, 反序列化可能会出现`local class incompatible`异常
这是基于Java的安全机制. 当序列化对象时, 如果该对象所属类没有serialVersionUID, Java编译器会对jvm中该类的Class文件进行摘要算法生成一个
serialVersionUID(version1). 保存在序列化结果中. 当反序列化时, jvm会再次对jvm中Class文件摘要生成一个serialVersionUID(version2). 当且仅当被序列化对象的version1=version2时,
才会将反序列化结果加载入jvm中, 否则视为不安全, 抛出`local class incompatible`异常.
这样存在的问题就是, 当对象被序列化后, 其所属类只要进行过任何改动,会导致摘要算法算出的serialVersionUID变化.
从而version1 != version2导致抛出异常.
例如序列化对象存储在磁盘中后, jvm停止, 并且对其所属类进行修改. 再次启动jvm, 当对该对象序列化时就会抛异常.
不参与序列化
> 静态变量不参与序列化 (序列化不保存静态变量的状态)
> 被Transient修饰的成员变量不参与序列化
> 父子类中, 如果父类没有序列化, 子类序列化时, 父类的成员不会参与序列化
这种情况多出现在继承关系, 将common的一些属性定义在父类, 当父类没有实现Serializable接口的情况下, 序列化子类时, 父类成员属性不会参与到序列化中去.
有员工做抽象时, 将公共属性放在父类, 但父类没有实现Serializable接口, 导致了自雷序列化时丢失属性, 进而项目报错, 找半天错才发现.
存储规则
同一对象多次写入同一文件时, 只会保存一个序列化后的对象a以及多个对a的引用
当同一个文件, 例如b. 当一个对象c多次在b文件中写入时, 不会保存多个序列化后的对象, 只会保存第一个被序列化后的对象d. 再次存储c时, 存储内容为d的引用.
如果再次存储时成员属性发生变化, 例如age值由1变为2, 那么本次存储会增加d的引用以及成员变化值.