序列化是把一个对象保存成一个二进制数组,通过转移这些数组可以达到持久化的目的;我们直接来研究二进制数据中到底存的是什么?
普通java类
package serialize; import java.io.*; /** * Created by ZWZS on 2018/1/23. */ public class Serialize implements Serializable { private static final long serialVersionUID = -6012417445159883067L; public int num=1390; public static void main(String[] args) { try { FileOutputStream fileOutputStream = new FileOutputStream("d:/serialize.dat"); ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream); Serialize serialize = new Serialize(); outputStream.writeObject(serialize); outputStream.flush(); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }打开d盘对应的文件
第一部分: 序列化文件头
首先 AC ED STREAM_MAGIC 声明使用了序列化协议(magic也就是魔数,用这个区分文件的,记得
class文件也有魔数);
00 05 : STREAM_VERSION 声明了序列化协议版本;
73: TC_OBJECT 声明这是一个新的对象
第二部分: 序列化类的描述信息,在此处类是 Serialize类
72: TC_CLASSDESC 声明这里开始是一个新类;
00 13: class类名字的长度(也就是完成类名的长度),此处是19,也就是后面19个字节表示的是完整类名;
73 65 72 69 61 6C 69 7A 65 2E 53 65 72 69 61 6C 69 7A 65 刚好19个表示完整的类名(此处需要
说明一下,这些数是16进制表示,二位表示一个字节,而字符本质是ASCII码存储,因此73 对应的ASCII码
是 s,65对应e....,我们的包名刚好是serialize,后面以此类推)
AC 8F 9A 30 53 E2 2E C5 这8个字节对应的是uid的编号,uid的作用是为了反序列时会对比UID的值,
如果一样才进行序列化;
02:标记号,声明该对象支持序列化;
00 01 该类包含的域(属性)的个数为1;(此处就一个num属性)
第三部分: 对象中各个属性项的描述
49: 域类型,49代表"I",也就是INT类型(和class文件类似);
00 03: 域名字的长度: 为3;
6E 75 6D: num属性的名称;
第四部分:输出该类的父类信息,此处没有父类(此处指的是序列化的父类,也就是实现了Serializable
接口的父类,Object没有实现)
因为此类没有父类,因此无第四部分信息,如果有,格式和第二部分一样;
78: TC_ENDBLOCKDATA,对象块结束的标志;
70: TC_NULL 说明没有其他超类标志;
第五部分 输出对象的属性值,如果属性是一个对象,还将序列化此对象,规则同第二部分;
00 00 05 6E: 1390的值;
详细信息请参考<深入分析java web技术内幕>37页;