新聞中心
凡事都要問為什么,在講解序列化概念和原理前,我們先來了解一下為什么需要序列化。

成都網(wǎng)絡公司-成都網(wǎng)站建設公司成都創(chuàng)新互聯(lián)公司10年經(jīng)驗成就非凡,專業(yè)從事網(wǎng)站設計、做網(wǎng)站,成都網(wǎng)頁設計,成都網(wǎng)頁制作,軟文營銷,1元廣告等。10年來已成功提供全面的成都網(wǎng)站建設方案,打造行業(yè)特色的成都網(wǎng)站建設案例,建站熱線:13518219792,我們期待您的來電!
為什么要序列化?
如果光看定義我想你很難一下子理解序列化的意義,那么我們可以從另一個角度來感受一下什么是序列化。
都玩過游戲么?玩過的同學應該知道游戲里有一個叫『存檔』的功能,每次不想玩的時候可以把當前進度存檔,下次有時間想玩的時候,直接載入存檔就可以接著玩了,這樣的好處是之前的游戲進度不會丟失,要是每次打開都重新玩估計大家也沒什么耐心了。
如果把面向對象的思想帶到游戲的世界,那在我們眼中不管是游戲角色還是游戲中的怪獸、裝備等等都可以看成是一個個對象:
- 角色對象(包含性別、等級、經(jīng)驗值、血量、傷害值、護甲值等屬性)
- 怪獸對象(包含類型、血量、等級等等屬性)
- 裝備對象(包含類型、傷害值、附加值等等屬性)
在玩游戲的過程中創(chuàng)建一個游戲角色就好像是創(chuàng)建了一個角色對象,拿到一套裝備就好像創(chuàng)建了一個裝備對象,路上遇到的怪獸等等也都是對象了。
我們再用計算機的思維去思考,創(chuàng)建的這些對象都是保存在內存中的,大家都知道內存的數(shù)據(jù)是短暫保留的,斷電之后是會消失的,但是游戲經(jīng)過手動存檔之后就算你關機幾天了,再次進入游戲讀取存檔,你會發(fā)現(xiàn)之前在游戲中創(chuàng)建的角色和裝備都還在呢,這就很奇怪了,明明內存的數(shù)據(jù)斷電就消失了,這是為什么?
稍加思考就知道,我們在存檔的過程中就是將內存中的數(shù)據(jù)存儲到電腦的硬盤中,硬盤的數(shù)據(jù)在關機斷電后是不會丟失的(別杠,硬盤損壞數(shù)據(jù)丟失先不考慮)。這個過程就是對象的持久化,也就是我們今天要講的對象序列化。對象的序列化逆過程就叫做反序列化,反序列化也很好理解就是將硬盤中的信息讀取出來形成對象。
什么是序列化?
前面引入游戲的例子是為了讓大家生動地理解什么是序列化和反序列化。簡單總結一下就是:
- 序列化是指將對象實例的狀態(tài)存到存儲媒體的過程
- 反序列化是指將存儲在存儲媒體中的對象狀態(tài)裝換成對象的過程
用更為抽象的概念來講:
序列化:把對象轉化為可傳輸?shù)淖止?jié)序列過程
反序列化:把字節(jié)序列還原為對象的過程
序列化的機制
序列化最終的目的是為了對象可以跨平臺存儲和進行網(wǎng)絡傳輸,而我們進行跨平臺存儲和網(wǎng)絡傳輸?shù)姆绞骄褪?IO,而 IO 支持的數(shù)據(jù)格式就是字節(jié)數(shù)組。
那現(xiàn)在的問題就是如何把對象轉換成字節(jié)數(shù)組?這個很好辦,一般的編程語言都有這個能力,可以很容易將對象轉成字節(jié)數(shù)組。
仔細一想,我們單方面的把對象轉成字節(jié)數(shù)組還不行,因為沒有規(guī)則的字節(jié)數(shù)組我們是沒辦法把對象的本來面目還原回來的,簡單說就是將對象轉成字節(jié)數(shù)組容易但是將字節(jié)數(shù)組還原成對象就難了,所以我們必須在把對象轉成字節(jié)數(shù)組的時候就制定一種規(guī)則(序列化),那么我們從 IO 流里面讀出數(shù)據(jù)的時候再以這種規(guī)則把對象還原回來(反序列化)。
還是拿上面游戲那個例子,我們將正在玩的游戲存檔到硬盤,序列化就是將一個個角色對象和裝備對象存儲到硬盤,然后留下一張原來對象的結構圖紙,反序列化就是將硬盤里一個個對象讀出來照著圖紙逐個還原恢復。
常見序列化的方式
序列化只是定義了拆解對象的具體規(guī)則,那這種規(guī)則肯定也是多種多樣的,比如現(xiàn)在常見的序列化方式有:JDK 原生、JSON、ProtoBuf、Hessian、Kryo等。
(1)JDK 原生
作為一個成熟的編程語言,JDK自帶了序列化方法。只需要類實現(xiàn)了Serializable接口,就可以通過ObjectOutputStream類將對象變成byte[]字節(jié)數(shù)組。
JDK 序列化會把對象類的描述信息和所有的屬性以及繼承的元數(shù)據(jù)都序列化為字節(jié)流,所以會導致生成的字節(jié)流相對比較大。
另外,這種序列化方式是 JDK 自帶的,因此不支持跨語言。
簡單總結一下:JDK 原生的序列化方式生成的字節(jié)流比較大,也不支持跨語言,因此在實際項目和框架中用的都比較少。
(2)ProtoBuf
谷歌推出的,是一種語言無關、平臺無關、可擴展的序列化結構數(shù)據(jù)的方法,它可用于通信協(xié)議、數(shù)據(jù)存儲等。序列化后體積小,一般用于對傳輸性能有較高要求的系統(tǒng)。
(4)Hessian
Hessian 是一個輕量級的二進制 web service 協(xié)議,主要用于傳輸二進制數(shù)據(jù)。
在傳輸數(shù)據(jù)前 Hessian 支持將對象序列化成二進制流,相對于 JDK 原生序列化,Hessian序列化之后體積更小,性能更優(yōu)。
(5)Kryo
Kryo 是一個 Java 序列化框架,號稱 Java 最快的序列化框架。Kryo 在序列化速度上很有優(yōu)勢,底層依賴于字節(jié)碼生成機制。
由于只能限定在 JVM 語言上,所以 Kryo 不支持跨語言使用。
(6)JSON
上面講的幾種序列化方式都是直接將對象變成二進制,也就是byte[]字節(jié)數(shù)組,這些方式都可以叫二進制方式。
JSON 序列化方式生成的是一串有規(guī)則的字符串,在可讀性上要優(yōu)于上面幾種方式,但是在體積上就沒什么優(yōu)勢了。
另外 JSON 是有規(guī)則的字符串,不跟任何編程語言綁定,天然上就具備了跨平臺。
總結一下:JSON 可讀性強,支持跨平臺,體積稍微遜色。
JSON 序列化常見的框架有:
fastJSON、Jackson、Gson 等。
序列化技術的選型
上面列舉的這些序列化技術各有優(yōu)缺點,不能簡單地說哪一種就是最好的,不然也不會有這么多序列化技術共存了。
既然有這么多序列化技術可供選擇,那在實際項目中如何選型呢?
我認為需要結合具體的項目來看,比較技術是服務于業(yè)務的。你可以從下面這幾個因素來考慮:
(1)協(xié)議是否支持跨平臺
如果一個大的系統(tǒng)有好多種語言進行混合開發(fā),那么就肯定不適合用有語言局限性的序列化協(xié)議,比如 JDK 原生、Kryo 這些只能用在 Java 語言范圍下,你用 JDK 原生方式進行序列化,用其他語言是無法反序列化的。
(2)序列化的速度
如果序列化的頻率非常高,那么選擇序列化速度快的協(xié)議會為你的系統(tǒng)性能提升不少。
(3)序列化生成的體積
如果頻繁的在網(wǎng)絡中傳輸?shù)臄?shù)據(jù)那就需要數(shù)據(jù)越小越好,小的數(shù)據(jù)傳輸快,也不占帶寬,也能整體提升系統(tǒng)的性能,因此序列化生成的體積就很關鍵了。
小結
(1)為什么我們要序列化?
因為我們需要將內存中的對象存儲到媒介中,或者我們需要將一個對象通過網(wǎng)絡傳輸?shù)搅硗庖粋€系統(tǒng)中。
(2)什么是序列化?
序列化就是把對象轉化為可傳輸?shù)淖止?jié)序列過程;反序列化就是把字節(jié)序列還原為對象的過程。
(3)序列化的機制
序列化最終的目的是為了對象可以跨平臺存儲和進行網(wǎng)絡傳輸,而我們進行跨平臺存儲和網(wǎng)絡傳輸?shù)姆绞骄褪?IO,而 IO 支持的數(shù)據(jù)格式就是字節(jié)數(shù)組。
將對象轉成字節(jié)數(shù)組的時候需要制定一種規(guī)則,這種規(guī)則就是序列化機制。
(4)常見序列化的方式
現(xiàn)在常見的序列化方式有:JDK 原生、JSON、ProtoBuf、Hessian、Kryo等。
(5)序列化技術的選型
選型最重要的就是要考慮這三個方面:協(xié)議是否支持跨平臺、序列化的速度、序列化生成的體積。
本文題目:面試官:詳細說說你對序列化的理解
文章來源:http://m.fisionsoft.com.cn/article/cocggog.html


咨詢
建站咨詢
