序列版本ID:序列化时会写入序列版本ID,读时对比序列版本ID是否相同,不同则导致InvalidClassException。
如果不写序列版本ID,JVM会自动生成,但不同JVM,应用的算法可能不同,可能导致序列版本ID不同,导致无法反序列化,建议写。
IDEA可自动生成,Ctrl+Alt+S,然后搜索Serializable class without 'serialVersionUID'并勾选,在序列化类那里Alt+Enter,点击Add 'serialVersionUID' field。
序列方式深拷贝:
import java.io.*; /** * 类成员变量中基本数据类型和String类型会默认拷贝,这些类型之外的类型默认不拷贝,共用引用。如果这些类型之外的类型也拷贝了,就是深拷贝。 */ public class DeepCloneBySerialization { public static void main(String[] args) throws Exception { Teacher teacher = new Teacher(); teacher.setAge(50); teacher.setName("Teacher_甲"); Student student1 = new Student(); student1.setAge(23); student1.setName("Student_甲"); student1.setTeacher(teacher); Teacher[] teacherArray = {teacher}; student1.setTeacherArray(teacherArray); Student student2 = student1.deepClone(); System.out.println(student2.getAge()); System.out.println(student2.getName()); System.out.println(student2.getTeacher().getAge()); System.out.println(student2.getTeacher().getName()); System.out.println(student2.getTeacherArray()[0].getName()); System.out.println("-----------------------"); student2.getTeacher().setAge(77); student2.getTeacher().setName("Teacher_乙"); System.out.println(teacher.getAge()); System.out.println(teacher.getName()); System.out.println(student2.getTeacher().getAge()); System.out.println(student2.getTeacher().getName()); System.out.println(student2.getTeacherArray()[0].getName()); } } class Teacher implements Serializable { private static final long serialVersionUID = -7383978843190364934L; private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Student implements Serializable { private static final long serialVersionUID = 5913268735291548932L; private int age; private String name; private Teacher teacher; private Teacher[] teacherArray = new Teacher[1]; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } public Teacher[] getTeacherArray() { return teacherArray; } public void setTeacherArray(Teacher[] teacherArray) { this.teacherArray = teacherArray; } public Student deepClone() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (Student)ois.readObject(); } }
转:
序列化考虑的因素:
(1)序列化的数据大小(影响传输效率)
(2)是否跨语言
举例:
hassian:Hessian 是一个支持跨语言传输的二进制序列化协议,相对于 Java 默认的序列化机制来说,Hessian 具有更好的性能和易用性,而且支持多种不同的语言实际上 Dubbo 采用的就是 Hessian 序列化来实现,只不过 Dubbo 对 Hessian 进行了重构,称 hassian2,性能更高 。
msgpack
protobuf (压缩率非常高):Protocol Buffer 的性能好,主要体现在 序列化后的数据体积小 & 序列化速度快,最终使得传输效率高,其原因如下:序列化速度快的原因:a. 编码 / 解码 方式简单(只需要简单的数学运算 = 位移等等)b. 采用 Protocol Buffer 自身的框架代码 和 编译器 共同完成序列化后的数据量体积小(即数据压缩效果好)的原因:a. 采用了独特的编码方式,如 Varint、Zigzag 编码方式等等b. 采用 T - L - V 的数据存储方式:减少了分隔符的使用 & 数据存储得紧凑
kyro:Kryo 是一种非常成熟的序列化实现,已经在 Hive、Storm)中使用得比较广泛,不过它不能跨语言. 目前 dubbo 已经在 2.6 版本支持 kyro 的序列化机制。它的性能要优于之前的hessian2
avro:Avro 是一个数据序列化系统,设计用于支持大批量数据交换的应用。它的主要特点有:支持二进制序列化方式,可以便捷,快速地处理大量数据;动态语言友好,Avro 提供的机制使动态语言可以方便地处理 Avro 数据。
json(跨语言特性、序列化效率高 ):JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相对于 XML 来说,JSON的字节流更小,而且可读性也非常好。现在 JSON 数据格式在企业运用是最普遍的JSON 序列化常用的开源工具有很多1. Jackson ( https://github.com/FasterXML/jackson )2. 阿里开源的 FastJson ( https://github.com/alibaba/fastjon )3. Google 的 GSON (https://github.com/google/gson)这几种 json 序列化工具中,Jackson 与 fastjson 要比 GSON 的性能要好,但是 Jackson、GSON 的稳定性要比 Fastjson 好。而 fastjson 的优势在于提供的 api 非常容易使用
jute(zookeeper)
技术层面1. 序列化空间开销,也就是序列化产生的结果大小,这个影响到传输的性能2. 序列化过程中消耗的时长,序列化消耗时间过长影响到业务的响应时间3. 序列化协议是否支持跨平台,跨语言。因为现在的架构更加灵活,如果存在异构系统通信需求,那么这个是必须要考虑的4. 可扩展性/兼容性,在实际业务开发中,系统往往需要随着需求的快速迭代来实现快速更新,这就要求我们采用的序列化协议基于良好的可扩展性/兼容性,比如在现有的序列化数据结构中新增一个业务字段,不会影响到现有的服务5. 技术的流行程度,越流行的技术意味着使用的公司多,那么很多坑都已经淌过并且得到了 解决,技术解决方案也相对成熟6. 学习难度和易用性选型建议1. 对性能要求不高的场景,可以采用基于 XML 的 SOAP 协议2. 对性能和间接性有比较高要求的场景,那么 Hessian、Protobuf、Thrift、Avro 都可以。3. 基于前后端分离,或者独立的对外的 api 服务,选用 JSON 是比较好的,对于调试、可读性都很不错4. Avro 设计理念偏于动态类型语言,那么这类的场景使用 Avro 是可以的各个序列化技术的性能比较这个地址有针对不同序列化技术进行性能比较: https://github.com/eishay/jvm-serializers/wiki