基本概念
- 把对象转换为字节序列的过程称为对象的序列化。
- 把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式 。
对象序列化包括如下步骤:
- 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
- 通过对象输出流的writeObject()方法写对象。
对象反序列化的步骤如下:
- 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
- 通过对象输入流的readObject()方法读取对象。
定义一个Person类实现Serializable接口
public class Person implements Serializable {1112 /**13 * 序列化ID14 */15 private static final long serialVersionUID = -5809782578272943999L;16 private int age;17 private String name;18 private String sex;1920 public int getAge() {21 return age;22 }2324 public String getName() {25 return name;26 }2728 public String getSex() {29 return sex;30 }3132 public void setAge(int age) {33 this.age = age;34 }3536 public void setName(String name) {37 this.name = name;38 }3940 public void setSex(String sex) {41 this.sex = sex;42 }43 }
序列化和反序列化代码
public class TestObjSerializeAndDeserialize {1819 public static void main(String[] args) throws Exception {20 SerializePerson();//序列化Person对象21 Person p = DeserializePerson();//反序列Perons对象22 System.out.println(MessageFormat.format("name={0},age={1},sex={2}",23 p.getName(), p.getAge(), p.getSex()));24 }2533 private static void SerializePerson() throws FileNotFoundException,34 IOException {35 Person person = new Person();36 person.setName("gacl");37 person.setAge(25);38 person.setSex("男");39 // ObjectOutputStream 对象输出流,//将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作//包装一个输出流对象40 ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(41 new File("E:/Person.txt")));42 oo.writeObject(person);43 System.out.println("Person对象序列化成功!");44 oo.close();45 }464755 private static Person DeserializePerson() throws Exception, IOException {56 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(57 new File("E:/Person.txt")));58 Person person = (Person) ois.readObject();59 System.out.println("Person对象反序列化成功!");60 return person;61 }6263 }
SerialversionUID的作用
如果不显式添加SerialversionUID,java编译器通过摘要算法给这个类默认生成一个UID,class文件即使多一个空格生成的UID也会不同。
当序列化一个对象后,对类进行了修改(添加属性或者方法),再反序列化时会报UID不一致的错误,而显式声明UID后反序列化得到的对象与修改后的类是一致的。
开源社区序列化API
java中实现的序列化效率是极低的,在小项目中使用还尚可,但对于高并发,对序列化速度要求比较高的项目是将会成为瓶颈问题,目前常见的一些序列化工具都比其效率高。
- json/xml
目前使用比较频繁的格式化数据工具,简单直观,可读性好,有jackson,gson,fastjson等等,效率比java原生的序列化快2到4倍。
- kryo
是一个快速序列化/反序列化工具,效率比java高出一个级别,序列化出来的结果,是其自定义的、独有的一种格式,体积更小,一般只用来进行序列化和反序列化,而不用于在多个系统、甚至多种语言间进行数据交换(目前 kryo 也只有 java 实现),目前已经有多家大公司使用,相对比较稳定。
- fst
与kryo类似,是apache组织的一个开源项目,完全兼容JDK序列化协议的系列化框架,序列化速度大概是JDK的4-10倍,大小是JDK大小的1/3左右。
- protostuff
是google在原来的protobuffer上的优化产品。使用起来也比较简单易用,目前效率也是最好的一种序列化工具。
