/**

*  轉載請注明作者longdick    http://longdick.iteye.com

*

*/

Java 序列化算法透析

Serialization (序列化)是一種將對象以一連串的字節描述的過程;反序列化 deserialization 是一種將這些字節重建成一個對象的過程。 Java 序列化 API 提供一種處理對象序列化的標准機制。在這里你能學到如何序列化一個對象,什么時候需要序列化以及 Java 序列化的算法,我們用一個實例來示范序列化以后的字節是如何描述一個對象的信息的。

序列化的必要性

Java 中,一切都是對象,在分布式環境中經常需要將 Object 從這一端網絡或設備傳遞到另一端。這就需要有一種可以在兩端傳輸數據的協議。 Java 序列化機制就是為了解決這個問題而產生。

如何序列化一個對象

一個對象能夠序列化的前提是實現 Serializable 接口, Serializable 接口沒有方法,更像是個標記。有了這個標記的 Class 就能被序列化機制處理。

import java.io.Serializable;

class TestSerial implements Serializable {

public byte version = 100;

public byte count = 0;

}

然后我們寫個程序將對象序列化並輸出。 ObjectOutputStream 能把 Object 輸出成 Byte 流。我們將 Byte 流暫時存儲到 temp.out 文件里。

public static void main(String args[]) throws IOException {

FileOutputStream fos = new FileOutputStream("temp.out");

ObjectOutputStream oos = new ObjectOutputStream(fos);

TestSerial ts = new TestSerial();

oos.writeObject(ts);

oos.flush();

oos.close();

}

如果要從持久的文件中讀取 Bytes 重建對象,我們可以使用 ObjectInputStream 。

public static void main(String args[]) throws IOException {

FileInputStream fis = new FileInputStream("temp.out");

ObjectInputStream oin = new ObjectInputStream(fis);

TestSerial ts = (TestSerial) oin.readObject();

System.out.println("version="+ts.version);

}

執行結果為

100.

對象的序列化格式

將一個對象序列化后是什么樣子呢?打開剛才我們將對象序列化輸出的 temp.out 文件,以 16 進制方式顯示。內容應該如下:

AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65

73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05

63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78

70 00 64

這一坨字節就是用來描述序列化以后的

TestSerial 對象的,我們注意到 TestSerial 類中只有兩個域:

public byte version = 100;

public byte count = 0;

且都是 byte 型,理論上存儲這兩個域只需要 2 個 byte ,但是實際上 temp.out 占據空間為 51bytes ,也就是說除了數據以外,還包括了對序列化對象的其他描述。

Java 的序列化算法

序列化算法一般會按步驟做如下事情:

l       將對象實例相關的類元數據輸出。

l       遞歸地輸出類的超類描述直到不再有超類。

l       類元數據完了以后,開始從最頂層的超類開始 輸出對象實例的實際數據值。

l       從上至下遞歸輸出實例的數據

我們用另一個更完整覆蓋所有可能出現的情況的例子來說明:

class parent implements Serializable {

int parentVersion = 10;

}

class contain implements Serializable{

int containVersion = 11;

}

public class SerialTest extends parent implements Serializable {

int version = 66;

contain con = new contain();

public int getVersion() {

return version;

}

public static void main(String args[]) throws IOException {

FileOutputStream fos = new FileOutputStream("temp.out");

ObjectOutputStream oos = new ObjectOutputStream(fos);

SerialTest st = new SerialTest();

oos.writeObject(st);

oos.flush();

oos.close();

}

}

這個例子是相當的直白啦。 SerialTest 類實現 了 Parent 超類,內部還持有一個 Container 對象。

序列化后的格式如下:

AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65

73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07

76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09

4C 63 6F 6E 74 61 69 6E 3B 7872 00 06 70 61 72

65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00

0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70

00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74

61 69 6E FC BB E6 0E FB CB 60 C7 02 00 0149 00

0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78

70 00 00 00 0B

我們來仔細看看這些字節都代表了啥。開頭部分,見顏色 :

AC ED: STREAM_MAGIC. 聲明使用了序列化協議 .

00 05: STREAM_VERSION. 序列化協議版本 .

0x73: TC_OBJECT. 聲明這是一個新的對象 .

序列化算法的第一步就是輸出對象相關類的描述。例子所示對象為 SerialTest 類實例,因此接下來輸出 SerialTest 類的描述。見顏色 :

0x72: TC_CLASSDESC. 聲明這里開始一個新 Class 。

00 0A: Class 名字的長度 .

53 65 72 69 61 6c 54 65 73 74: SerialTest,Class 類名 .

05 52 81 5A AC 66 02 F6: SerialVersionUID , 序列化 ID ,如果沒有指定,則會由算法隨機生成一個 8byte 的 ID.

0x02: 標記號 . 該值聲明該對象支持序列化。

00 02: 該類所包含的域個數。

接下來,算法輸出其中的一個域, int version=66 ;見顏色 :

0x49: 域類型 . 49 代表 "I", 也就是 Int.

00 07: 域名字的長度 .

76 65 72 73 69 6F 6E: version, 域名字描述 .

然后,算法輸出下一個域, contain con = new contain(); 這個有點特殊,是個對象。描述對象類型引用時需要使用 JVM 的標准對象簽名表示法,見顏色 :

0x4C: 域的類型 .

00 03: 域名字長度 .

63 6F 6E: 域名字描述, con

0x74: TC_STRING. 代表一個 new String. 用 String 來引用對象。

00 09: 該 String 長度 .

4C 63 6F 6E 74 61 69 6E 3B: Lcontain ;, JVM 的標准對象簽名表示法 .

0x78: TC_ENDBLOCKDATA, 對象數據塊結束的標志

. 接下來算法就會輸出超類也就是 Parent 類描述了,見顏色 :

0x72: TC_CLASSDESC. 聲明這個是個新類 .

00 06: 類名長度 .

70 61 72 65 6E 74: parent, 類名描述。

0E DB D2 BD 85 EE 63 7A: SerialVersionUID , 序列化 ID.

0x02: 標記號 . 該值聲明該對象支持序列化 .

00 01: 類中域的個數 .

下一步,輸出 parent 類的域描述, int parentVersion =100; 同見顏色 :

0x49: 域類型 . 49 代表 "I", 也就是 Int.

00 0D: 域名字長度 .

70 61 72 65 6E 74 56 65 72 73 69 6F 6E: parentVersion ,域名字描述。

0x78: TC_ENDBLOCKDATA, 對象塊結束的標志。

0x70: TC_NULL, 說明沒有其他超類的標志。 .

到此為止,算法已經對所有的類的描述都做了輸出。下一步就是把實例對象的實際值輸出了。這時候是從 parent Class 的域開始的,見顏色 :

00 00 00 0A: 10, parentVersion 域的值 .

還有 SerialTest 類的域:

00 00 00 42: 66, version 域的值 .

再往后的 bytes 比較有意思,算法需要描述 contain 類的信息,要記住,現在還沒有對 contain 類進行過描述,見顏色 :

0x73: TC_OBJECT, 聲明這是一個新的對象 .

0x72: TC_CLASSDESC 聲明這里開始一個新 Class.

00 07: 類名的長度 .

63 6F 6E 74 61 69 6E: contain, 類名描述 .

FC BB E6 0E FB CB 60 C7: SerialVersionUID , 序列化 ID.

0x02: Various flags. 標記號 . 該值聲明該對象支持序列化

00 01: 類內的域個數。

. 輸出 contain 的唯一的域描述, int containVersion =11 ;

0x49: 域類型 . 49 代表 "I", 也就是 Int..

00 0E: 域名字長度 .

63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E: containVersion , 域名字描述 .

0x78: TC_ENDBLOCKDATA 對象塊結束的標志 .

這時,序列化算法會檢查 contain 是否有超類,如果有的話會接着輸出。

0x70:TC_NULL ,沒有超類了。

最后,將 contain 類實際域值輸出。

00 00 00 0B: 11, containVersion 的值 .

OK, 我們討論了 java 序列化的機制和原理,希望能對同學們有所幫助。

參考資料:

java序列化算法透析_Java序列化算法透析相关推荐

  1. java序列化算法透析_Java序列化机制与原理的深入分析

    Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程.Java序列化API提供一 ...

  2. java反序列化多个对象_java 序列化与反序列化多个对象 抛出异常

    jdk 1.8 IEDA 设置可以追加写入后,向目标文件序列化多个同一对象,再序列化出来时,因为反序列化时头部信息只读取一次,报出异常. 请问该怎么解决?或者代码写的有问题? import java. ...

  3. java序列化和反序列化工具_Java 序列化和反序列化工具类并解决StreamCorruptedException问题 | 学步园...

    问题: 若通过ObjectOutputStream向一个文件中多次以追加的方式写入Object,为什么用ObjectInputStream读取这些Object时,会产生StreamCorruptedE ...

  4. java集合笔试编程题_Java 基础算法及编程笔试题集合

    1. 斯诺克台球共有15个一分球,2,3,4,5,6,7分球各一个,规则是先打一个最低分球,然后可以打一个其他分值的球,如此反复,如果台面还有更低分值的球,打入的高分球计分,同时拿出来放回原位置,要求 ...

  5. java输出到空心三角形_java经典算法_019打印三角形(空心,实心) | 学步园

    打印三角形(空心,实心) package com.arithmetic; /** * 打印三角形(空心,实心) * * @author Administrator * */ public class ...

  6. java序列化原理_Java序列化机制和原理

    Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程.Java序列化API提供一 ...

  7. 推荐算法炼丹笔记:序列化推荐系统

    作者:一元 公众号:炼丹笔记 特约审稿:杰少 背景 序列推荐系统(SRS)不同于传统推荐系统(RSs)包括协同过滤和基于内容的过滤,SRSs试图理解和建模用户的连续行为.用户与物品之间的交互作用以及用 ...

  8. 数据结构与算法之二叉树的序列化和反序列化及判断一棵树是否为平衡二叉树

    数据结构与算法之二叉树的序列化和反序列化及判断一棵树是否为平衡而二叉树 目录 二叉树的序列化和反序列化 判断一棵树是否为平衡而二叉树 1. 二叉树的序列化和反序列化 1. 递归版本序列化和反序列化 代 ...

  9. java动态分区分配算法,操作系统_动态分区分配算法课程设计_java版

    <操作系统_动态分区分配算法课程设计_java版>由会员分享,可在线阅读,更多相关<操作系统_动态分区分配算法课程设计_java版(13页珍藏版)>请在人人文库网上搜索. 1. ...

最新文章

  1. 【C】——如何用线程进行参数的传递
  2. yolov5模型训练
  3. Python的日志记录-logging模块的使用
  4. linux用户恢复正常,Linux系统用户口令安全恢复方法
  5. c#计算 坐标点与坐标点之间的距离
  6. 文字不间断滚动(转)
  7. 微信用久了,越来越占内存怎么办?
  8. 强烈推荐asp.net数据访问的官方指南系列 (Data Access Tutorials)
  9. Ubuntu 14.04 安装Octave
  10. 可视化排班管理_呼叫中心外包之管理要点与数据分析对策
  11. e480 黑苹果_记一次黑苹果PC装机全过程
  12. 推荐几个学习GIS的社区
  13. 燕秀计算机打印区域文字高度,燕秀工具命令.doc
  14. 一个完整的机器学习模型的流程
  15. TI DSP处理器中CMD 文件的那些事儿
  16. Dragonfly单机部署比redis快25倍的缓存中间件
  17. 基于Spring Boot的个人博客系统的设计与实现 毕业设计-附源码271611
  18. App Thinning(为什么苹果app上传时的包比在appStore下载下来的包大很多)
  19. 场景化、细分化来袭:从2022深圳时尚家居设计周看家居行业的重塑之路
  20. 手把手教学京东api接口全部操作过程

热门文章

  1. 上海联彤TV盒子安装apk
  2. 基于c语言实现的个人理财系统,基于Android的个人理财系统—设计和实现-论文最终版.doc...
  3. 【一致性仿真】Group-Bipartite Consensus in the Networks With Cooperative-Competitive Interactions
  4. 在进行USB CDC类开发时,无法发送64整数倍的数据(续)
  5. ALTER TABLE 语句添加字段
  6. 计算机视觉——DoG和LoG算子
  7. c语言选择结构程序设计实验报告6,c语言-选择结构程序设计实验报告4.doc
  8. 证件类型、证件号码、性别、出生日期校验(身份证、户口簿、港澳居民居住证、台湾居民居住证、港澳居民来往内地通行证、台湾居民来往大陆通行证、境外永久居住证、外国人永久居留身份证、护照、其他)
  9. 如何着手写一篇医学综述?
  10. 论文笔记之Soft Q-learning